cannam@148: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors cannam@148: // Licensed under the MIT License: cannam@148: // cannam@148: // Permission is hereby granted, free of charge, to any person obtaining a copy cannam@148: // of this software and associated documentation files (the "Software"), to deal cannam@148: // in the Software without restriction, including without limitation the rights cannam@148: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cannam@148: // copies of the Software, and to permit persons to whom the Software is cannam@148: // furnished to do so, subject to the following conditions: cannam@148: // cannam@148: // The above copyright notice and this permission notice shall be included in cannam@148: // all copies or substantial portions of the Software. cannam@148: // cannam@148: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cannam@148: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cannam@148: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cannam@148: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cannam@148: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, cannam@148: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN cannam@148: // THE SOFTWARE. cannam@148: cannam@148: #ifndef CAPNP_ANY_H_ cannam@148: #define CAPNP_ANY_H_ cannam@148: cannam@148: #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) cannam@148: #pragma GCC system_header cannam@148: #endif cannam@148: cannam@148: #include "layout.h" cannam@148: #include "pointer-helpers.h" cannam@148: #include "orphan.h" cannam@148: #include "list.h" cannam@148: cannam@148: namespace capnp { cannam@148: cannam@148: class StructSchema; cannam@148: class ListSchema; cannam@148: class InterfaceSchema; cannam@148: class Orphanage; cannam@148: class ClientHook; cannam@148: class PipelineHook; cannam@148: struct PipelineOp; cannam@148: struct AnyPointer; cannam@148: cannam@148: struct AnyList { cannam@148: AnyList() = delete; cannam@148: cannam@148: class Reader; cannam@148: class Builder; cannam@148: }; cannam@148: cannam@148: struct AnyStruct { cannam@148: AnyStruct() = delete; cannam@148: cannam@148: class Reader; cannam@148: class Builder; cannam@148: class Pipeline; cannam@148: }; cannam@148: cannam@148: template<> cannam@148: struct List { cannam@148: List() = delete; cannam@148: cannam@148: class Reader; cannam@148: class Builder; cannam@148: }; cannam@148: cannam@148: namespace _ { // private cannam@148: template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; cannam@148: template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; cannam@148: template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; cannam@148: } // namespace _ (private) cannam@148: cannam@148: // ======================================================================================= cannam@148: // AnyPointer! cannam@148: cannam@148: enum class Equality { cannam@148: NOT_EQUAL, cannam@148: EQUAL, cannam@148: UNKNOWN_CONTAINS_CAPS cannam@148: }; cannam@148: cannam@148: kj::StringPtr KJ_STRINGIFY(Equality res); cannam@148: cannam@148: struct AnyPointer { cannam@148: // Reader/Builder for the `AnyPointer` field type, i.e. a pointer that can point to an arbitrary cannam@148: // object. cannam@148: cannam@148: AnyPointer() = delete; cannam@148: cannam@148: class Reader { cannam@148: public: cannam@148: typedef AnyPointer Reads; cannam@148: cannam@148: Reader() = default; cannam@148: inline Reader(_::PointerReader reader): reader(reader) {} cannam@148: cannam@148: inline MessageSize targetSize() const; cannam@148: // Get the total size of the target object and all its children. cannam@148: cannam@148: inline PointerType getPointerType() const; cannam@148: cannam@148: inline bool isNull() const { return getPointerType() == PointerType::NULL_; } cannam@148: inline bool isStruct() const { return getPointerType() == PointerType::STRUCT; } cannam@148: inline bool isList() const { return getPointerType() == PointerType::LIST; } cannam@148: inline bool isCapability() const { return getPointerType() == PointerType::CAPABILITY; } cannam@148: cannam@148: Equality equals(AnyPointer::Reader right); cannam@148: bool operator==(AnyPointer::Reader right); cannam@148: inline bool operator!=(AnyPointer::Reader right) { cannam@148: return !(*this == right); cannam@148: } cannam@148: cannam@148: template cannam@148: inline ReaderFor getAs() const; cannam@148: // Valid for T = any generated struct type, interface type, List, Text, or Data. cannam@148: cannam@148: template cannam@148: inline ReaderFor getAs(StructSchema schema) const; cannam@148: // Only valid for T = DynamicStruct. Requires `#include `. cannam@148: cannam@148: template cannam@148: inline ReaderFor getAs(ListSchema schema) const; cannam@148: // Only valid for T = DynamicList. Requires `#include `. cannam@148: cannam@148: template cannam@148: inline ReaderFor getAs(InterfaceSchema schema) const; cannam@148: // Only valid for T = DynamicCapability. Requires `#include `. cannam@148: cannam@148: #if !CAPNP_LITE cannam@148: kj::Own getPipelinedCap(kj::ArrayPtr ops) const; cannam@148: // Used by RPC system to implement pipelining. Applications generally shouldn't use this cannam@148: // directly. cannam@148: #endif // !CAPNP_LITE cannam@148: cannam@148: private: cannam@148: _::PointerReader reader; cannam@148: friend struct AnyPointer; cannam@148: friend class Orphanage; cannam@148: friend class CapReaderContext; cannam@148: friend struct _::PointerHelpers; cannam@148: }; cannam@148: cannam@148: class Builder { cannam@148: public: cannam@148: typedef AnyPointer Builds; cannam@148: cannam@148: Builder() = delete; cannam@148: inline Builder(decltype(nullptr)) {} cannam@148: inline Builder(_::PointerBuilder builder): builder(builder) {} cannam@148: cannam@148: inline MessageSize targetSize() const; cannam@148: // Get the total size of the target object and all its children. cannam@148: cannam@148: inline PointerType getPointerType(); cannam@148: cannam@148: inline bool isNull() { return getPointerType() == PointerType::NULL_; } cannam@148: inline bool isStruct() { return getPointerType() == PointerType::STRUCT; } cannam@148: inline bool isList() { return getPointerType() == PointerType::LIST; } cannam@148: inline bool isCapability() { return getPointerType() == PointerType::CAPABILITY; } cannam@148: cannam@148: inline Equality equals(AnyPointer::Reader right) { cannam@148: return asReader().equals(right); cannam@148: } cannam@148: inline bool operator==(AnyPointer::Reader right) { cannam@148: return asReader() == right; cannam@148: } cannam@148: inline bool operator!=(AnyPointer::Reader right) { cannam@148: return !(*this == right); cannam@148: } cannam@148: cannam@148: inline void clear(); cannam@148: // Set to null. cannam@148: cannam@148: template cannam@148: inline BuilderFor getAs(); cannam@148: // Valid for T = any generated struct type, List, Text, or Data. cannam@148: cannam@148: template cannam@148: inline BuilderFor getAs(StructSchema schema); cannam@148: // Only valid for T = DynamicStruct. Requires `#include `. cannam@148: cannam@148: template cannam@148: inline BuilderFor getAs(ListSchema schema); cannam@148: // Only valid for T = DynamicList. Requires `#include `. cannam@148: cannam@148: template cannam@148: inline BuilderFor getAs(InterfaceSchema schema); cannam@148: // Only valid for T = DynamicCapability. Requires `#include `. cannam@148: cannam@148: template cannam@148: inline BuilderFor initAs(); cannam@148: // Valid for T = any generated struct type. cannam@148: cannam@148: template cannam@148: inline BuilderFor initAs(uint elementCount); cannam@148: // Valid for T = List, Text, or Data. cannam@148: cannam@148: template cannam@148: inline BuilderFor initAs(StructSchema schema); cannam@148: // Only valid for T = DynamicStruct. Requires `#include `. cannam@148: cannam@148: template cannam@148: inline BuilderFor initAs(ListSchema schema, uint elementCount); cannam@148: // Only valid for T = DynamicList. Requires `#include `. cannam@148: cannam@148: inline AnyList::Builder initAsAnyList(ElementSize elementSize, uint elementCount); cannam@148: // Note: Does not accept INLINE_COMPOSITE for elementSize. cannam@148: cannam@148: inline List::Builder initAsListOfAnyStruct( cannam@148: uint16_t dataWordCount, uint16_t pointerCount, uint elementCount); cannam@148: cannam@148: inline AnyStruct::Builder initAsAnyStruct(uint16_t dataWordCount, uint16_t pointerCount); cannam@148: cannam@148: template cannam@148: inline void setAs(ReaderFor value); cannam@148: // Valid for ReaderType = T::Reader for T = any generated struct type, List, Text, Data, cannam@148: // DynamicStruct, or DynamicList (the dynamic types require `#include `). cannam@148: cannam@148: template cannam@148: inline void setAs(std::initializer_list>> list); cannam@148: // Valid for T = List. cannam@148: cannam@148: template cannam@148: inline void setCanonicalAs(ReaderFor value); cannam@148: cannam@148: inline void set(Reader value) { builder.copyFrom(value.reader); } cannam@148: // Set to a copy of another AnyPointer. cannam@148: cannam@148: inline void setCanonical(Reader value) { builder.copyFrom(value.reader, true); } cannam@148: cannam@148: template cannam@148: inline void adopt(Orphan&& orphan); cannam@148: // Valid for T = any generated struct type, List, Text, Data, DynamicList, DynamicStruct, cannam@148: // or DynamicValue (the dynamic types require `#include `). cannam@148: cannam@148: template cannam@148: inline Orphan disownAs(); cannam@148: // Valid for T = any generated struct type, List, Text, Data. cannam@148: cannam@148: template cannam@148: inline Orphan disownAs(StructSchema schema); cannam@148: // Only valid for T = DynamicStruct. Requires `#include `. cannam@148: cannam@148: template cannam@148: inline Orphan disownAs(ListSchema schema); cannam@148: // Only valid for T = DynamicList. Requires `#include `. cannam@148: cannam@148: template cannam@148: inline Orphan disownAs(InterfaceSchema schema); cannam@148: // Only valid for T = DynamicCapability. Requires `#include `. cannam@148: cannam@148: inline Orphan disown(); cannam@148: // Disown without a type. cannam@148: cannam@148: inline Reader asReader() const { return Reader(builder.asReader()); } cannam@148: inline operator Reader() const { return Reader(builder.asReader()); } cannam@148: cannam@148: private: cannam@148: _::PointerBuilder builder; cannam@148: friend class Orphanage; cannam@148: friend class CapBuilderContext; cannam@148: friend struct _::PointerHelpers; cannam@148: }; cannam@148: cannam@148: #if !CAPNP_LITE cannam@148: class Pipeline { cannam@148: public: cannam@148: typedef AnyPointer Pipelines; cannam@148: cannam@148: inline Pipeline(decltype(nullptr)) {} cannam@148: inline explicit Pipeline(kj::Own&& hook): hook(kj::mv(hook)) {} cannam@148: cannam@148: Pipeline noop(); cannam@148: // Just make a copy. cannam@148: cannam@148: Pipeline getPointerField(uint16_t pointerIndex); cannam@148: // Deprecated. In the future, we should use .asAnyStruct.getPointerField. cannam@148: cannam@148: inline AnyStruct::Pipeline asAnyStruct(); cannam@148: cannam@148: kj::Own asCap(); cannam@148: // Expect that the result is a capability and construct a pipelined version of it now. cannam@148: cannam@148: inline kj::Own releasePipelineHook() { return kj::mv(hook); } cannam@148: // For use by RPC implementations. cannam@148: cannam@148: template ) == Kind::INTERFACE>> cannam@148: inline operator T() { return T(asCap()); } cannam@148: cannam@148: private: cannam@148: kj::Own hook; cannam@148: kj::Array ops; cannam@148: cannam@148: inline Pipeline(kj::Own&& hook, kj::Array&& ops) cannam@148: : hook(kj::mv(hook)), ops(kj::mv(ops)) {} cannam@148: cannam@148: friend class LocalClient; cannam@148: friend class PipelineHook; cannam@148: friend class AnyStruct::Pipeline; cannam@148: }; cannam@148: #endif // !CAPNP_LITE cannam@148: }; cannam@148: cannam@148: template <> cannam@148: class Orphan { cannam@148: // An orphaned object of unknown type. cannam@148: cannam@148: public: cannam@148: Orphan() = default; cannam@148: KJ_DISALLOW_COPY(Orphan); cannam@148: Orphan(Orphan&&) = default; cannam@148: inline Orphan(_::OrphanBuilder&& builder) cannam@148: : builder(kj::mv(builder)) {} cannam@148: cannam@148: Orphan& operator=(Orphan&&) = default; cannam@148: cannam@148: template cannam@148: inline Orphan(Orphan&& other): builder(kj::mv(other.builder)) {} cannam@148: template cannam@148: inline Orphan& operator=(Orphan&& other) { builder = kj::mv(other.builder); return *this; } cannam@148: // Cast from typed orphan. cannam@148: cannam@148: // It's not possible to get an AnyPointer::{Reader,Builder} directly since there is no cannam@148: // underlying pointer (the pointer would normally live in the parent, but this object is cannam@148: // orphaned). It is possible, however, to request typed readers/builders. cannam@148: cannam@148: template cannam@148: inline BuilderFor getAs(); cannam@148: template cannam@148: inline BuilderFor getAs(StructSchema schema); cannam@148: template cannam@148: inline BuilderFor getAs(ListSchema schema); cannam@148: template cannam@148: inline typename T::Client getAs(InterfaceSchema schema); cannam@148: template cannam@148: inline ReaderFor getAsReader() const; cannam@148: template cannam@148: inline ReaderFor getAsReader(StructSchema schema) const; cannam@148: template cannam@148: inline ReaderFor getAsReader(ListSchema schema) const; cannam@148: template cannam@148: inline typename T::Client getAsReader(InterfaceSchema schema) const; cannam@148: cannam@148: template cannam@148: inline Orphan releaseAs(); cannam@148: template cannam@148: inline Orphan releaseAs(StructSchema schema); cannam@148: template cannam@148: inline Orphan releaseAs(ListSchema schema); cannam@148: template cannam@148: inline Orphan releaseAs(InterfaceSchema schema); cannam@148: // Down-cast the orphan to a specific type. cannam@148: cannam@148: inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } cannam@148: inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } cannam@148: cannam@148: private: cannam@148: _::OrphanBuilder builder; cannam@148: cannam@148: template cannam@148: friend struct _::PointerHelpers; cannam@148: friend class Orphanage; cannam@148: template cannam@148: friend class Orphan; cannam@148: friend class AnyPointer::Builder; cannam@148: }; cannam@148: cannam@148: template struct AnyTypeFor_; cannam@148: template <> struct AnyTypeFor_ { typedef AnyStruct Type; }; cannam@148: template <> struct AnyTypeFor_ { typedef AnyList Type; }; cannam@148: cannam@148: template cannam@148: using AnyTypeFor = typename AnyTypeFor_::Type; cannam@148: cannam@148: template cannam@148: inline ReaderFor>> toAny(T&& value) { cannam@148: return ReaderFor>>( cannam@148: _::PointerHelpers>::getInternalReader(value)); cannam@148: } cannam@148: template cannam@148: inline BuilderFor>> toAny(T&& value) { cannam@148: return BuilderFor>>( cannam@148: _::PointerHelpers>::getInternalBuilder(kj::mv(value))); cannam@148: } cannam@148: cannam@148: template <> cannam@148: struct List { cannam@148: // Note: This cannot be used for a list of structs, since such lists are not encoded as pointer cannam@148: // lists! Use List. cannam@148: cannam@148: List() = delete; cannam@148: cannam@148: class Reader { cannam@148: public: cannam@148: typedef List Reads; cannam@148: cannam@148: inline Reader(): reader(ElementSize::POINTER) {} cannam@148: inline explicit Reader(_::ListReader reader): reader(reader) {} cannam@148: cannam@148: inline uint size() const { return unbound(reader.size() / ELEMENTS); } cannam@148: inline AnyPointer::Reader operator[](uint index) const { cannam@148: KJ_IREQUIRE(index < size()); cannam@148: return AnyPointer::Reader(reader.getPointerElement(bounded(index) * ELEMENTS)); cannam@148: } cannam@148: cannam@148: typedef _::IndexingIterator Iterator; cannam@148: inline Iterator begin() const { return Iterator(this, 0); } cannam@148: inline Iterator end() const { return Iterator(this, size()); } cannam@148: cannam@148: private: cannam@148: _::ListReader reader; cannam@148: template cannam@148: friend struct _::PointerHelpers; cannam@148: template cannam@148: friend struct List; cannam@148: friend class Orphanage; cannam@148: template cannam@148: friend struct ToDynamic_; cannam@148: }; cannam@148: cannam@148: class Builder { cannam@148: public: cannam@148: typedef List Builds; cannam@148: cannam@148: Builder() = delete; cannam@148: inline Builder(decltype(nullptr)): builder(ElementSize::POINTER) {} cannam@148: inline explicit Builder(_::ListBuilder builder): builder(builder) {} cannam@148: cannam@148: inline operator Reader() const { return Reader(builder.asReader()); } cannam@148: inline Reader asReader() const { return Reader(builder.asReader()); } cannam@148: cannam@148: inline uint size() const { return unbound(builder.size() / ELEMENTS); } cannam@148: inline AnyPointer::Builder operator[](uint index) { cannam@148: KJ_IREQUIRE(index < size()); cannam@148: return AnyPointer::Builder(builder.getPointerElement(bounded(index) * ELEMENTS)); cannam@148: } cannam@148: cannam@148: typedef _::IndexingIterator Iterator; cannam@148: inline Iterator begin() { return Iterator(this, 0); } cannam@148: inline Iterator end() { return Iterator(this, size()); } cannam@148: cannam@148: private: cannam@148: _::ListBuilder builder; cannam@148: template cannam@148: friend struct _::PointerHelpers; cannam@148: friend class Orphanage; cannam@148: template cannam@148: friend struct ToDynamic_; cannam@148: }; cannam@148: }; cannam@148: cannam@148: class AnyStruct::Reader { cannam@148: public: cannam@148: typedef AnyStruct Reads; cannam@148: cannam@148: Reader() = default; cannam@148: inline Reader(_::StructReader reader): _reader(reader) {} cannam@148: cannam@148: template ) == Kind::STRUCT>> cannam@148: inline Reader(T&& value) cannam@148: : _reader(_::PointerHelpers>::getInternalReader(kj::fwd(value))) {} cannam@148: cannam@148: kj::ArrayPtr getDataSection() { cannam@148: return _reader.getDataSectionAsBlob(); cannam@148: } cannam@148: List::Reader getPointerSection() { cannam@148: return List::Reader(_reader.getPointerSectionAsList()); cannam@148: } cannam@148: cannam@148: kj::Array canonicalize() { cannam@148: return _reader.canonicalize(); cannam@148: } cannam@148: cannam@148: Equality equals(AnyStruct::Reader right); cannam@148: bool operator==(AnyStruct::Reader right); cannam@148: inline bool operator!=(AnyStruct::Reader right) { cannam@148: return !(*this == right); cannam@148: } cannam@148: cannam@148: template cannam@148: ReaderFor as() const { cannam@148: // T must be a struct type. cannam@148: return typename T::Reader(_reader); cannam@148: } cannam@148: private: cannam@148: _::StructReader _reader; cannam@148: cannam@148: template cannam@148: friend struct _::PointerHelpers; cannam@148: friend class Orphanage; cannam@148: }; cannam@148: cannam@148: class AnyStruct::Builder { cannam@148: public: cannam@148: typedef AnyStruct Builds; cannam@148: cannam@148: inline Builder(decltype(nullptr)) {} cannam@148: inline Builder(_::StructBuilder builder): _builder(builder) {} cannam@148: cannam@148: #if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. cannam@148: template ) == Kind::STRUCT>> cannam@148: inline Builder(T&& value) cannam@148: : _builder(_::PointerHelpers>::getInternalBuilder(kj::fwd(value))) {} cannam@148: #endif cannam@148: cannam@148: inline kj::ArrayPtr getDataSection() { cannam@148: return _builder.getDataSectionAsBlob(); cannam@148: } cannam@148: List::Builder getPointerSection() { cannam@148: return List::Builder(_builder.getPointerSectionAsList()); cannam@148: } cannam@148: cannam@148: inline Equality equals(AnyStruct::Reader right) { cannam@148: return asReader().equals(right); cannam@148: } cannam@148: inline bool operator==(AnyStruct::Reader right) { cannam@148: return asReader() == right; cannam@148: } cannam@148: inline bool operator!=(AnyStruct::Reader right) { cannam@148: return !(*this == right); cannam@148: } cannam@148: cannam@148: inline operator Reader() const { return Reader(_builder.asReader()); } cannam@148: inline Reader asReader() const { return Reader(_builder.asReader()); } cannam@148: cannam@148: template cannam@148: BuilderFor as() { cannam@148: // T must be a struct type. cannam@148: return typename T::Builder(_builder); cannam@148: } cannam@148: private: cannam@148: _::StructBuilder _builder; cannam@148: friend class Orphanage; cannam@148: friend class CapBuilderContext; cannam@148: }; cannam@148: cannam@148: #if !CAPNP_LITE cannam@148: class AnyStruct::Pipeline { cannam@148: public: cannam@148: inline Pipeline(decltype(nullptr)): typeless(nullptr) {} cannam@148: inline explicit Pipeline(AnyPointer::Pipeline&& typeless) cannam@148: : typeless(kj::mv(typeless)) {} cannam@148: cannam@148: inline AnyPointer::Pipeline getPointerField(uint16_t pointerIndex) { cannam@148: // Return a new Promise representing a sub-object of the result. `pointerIndex` is the index cannam@148: // of the sub-object within the pointer section of the result (the result must be a struct). cannam@148: // cannam@148: // TODO(perf): On GCC 4.8 / Clang 3.3, use rvalue qualifiers to avoid the need for copies. cannam@148: // Also make `ops` into a Vector to optimize this. cannam@148: return typeless.getPointerField(pointerIndex); cannam@148: } cannam@148: cannam@148: private: cannam@148: AnyPointer::Pipeline typeless; cannam@148: }; cannam@148: #endif // !CAPNP_LITE cannam@148: cannam@148: class List::Reader { cannam@148: public: cannam@148: typedef List Reads; cannam@148: cannam@148: inline Reader(): reader(ElementSize::INLINE_COMPOSITE) {} cannam@148: inline explicit Reader(_::ListReader reader): reader(reader) {} cannam@148: cannam@148: inline uint size() const { return unbound(reader.size() / ELEMENTS); } cannam@148: inline AnyStruct::Reader operator[](uint index) const { cannam@148: KJ_IREQUIRE(index < size()); cannam@148: return AnyStruct::Reader(reader.getStructElement(bounded(index) * ELEMENTS)); cannam@148: } cannam@148: cannam@148: typedef _::IndexingIterator Iterator; cannam@148: inline Iterator begin() const { return Iterator(this, 0); } cannam@148: inline Iterator end() const { return Iterator(this, size()); } cannam@148: cannam@148: private: cannam@148: _::ListReader reader; cannam@148: template cannam@148: friend struct _::PointerHelpers; cannam@148: template cannam@148: friend struct List; cannam@148: friend class Orphanage; cannam@148: template cannam@148: friend struct ToDynamic_; cannam@148: }; cannam@148: cannam@148: class List::Builder { cannam@148: public: cannam@148: typedef List Builds; cannam@148: cannam@148: Builder() = delete; cannam@148: inline Builder(decltype(nullptr)): builder(ElementSize::INLINE_COMPOSITE) {} cannam@148: inline explicit Builder(_::ListBuilder builder): builder(builder) {} cannam@148: cannam@148: inline operator Reader() const { return Reader(builder.asReader()); } cannam@148: inline Reader asReader() const { return Reader(builder.asReader()); } cannam@148: cannam@148: inline uint size() const { return unbound(builder.size() / ELEMENTS); } cannam@148: inline AnyStruct::Builder operator[](uint index) { cannam@148: KJ_IREQUIRE(index < size()); cannam@148: return AnyStruct::Builder(builder.getStructElement(bounded(index) * ELEMENTS)); cannam@148: } cannam@148: cannam@148: typedef _::IndexingIterator Iterator; cannam@148: inline Iterator begin() { return Iterator(this, 0); } cannam@148: inline Iterator end() { return Iterator(this, size()); } cannam@148: cannam@148: private: cannam@148: _::ListBuilder builder; cannam@148: template cannam@148: friend struct _::PointerHelpers; cannam@148: friend class Orphanage; cannam@148: template cannam@148: friend struct ToDynamic_; cannam@148: }; cannam@148: cannam@148: class AnyList::Reader { cannam@148: public: cannam@148: typedef AnyList Reads; cannam@148: cannam@148: inline Reader(): _reader(ElementSize::VOID) {} cannam@148: inline Reader(_::ListReader reader): _reader(reader) {} cannam@148: cannam@148: #if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. cannam@148: template ) == Kind::LIST>> cannam@148: inline Reader(T&& value) cannam@148: : _reader(_::PointerHelpers>::getInternalReader(kj::fwd(value))) {} cannam@148: #endif cannam@148: cannam@148: inline ElementSize getElementSize() { return _reader.getElementSize(); } cannam@148: inline uint size() { return unbound(_reader.size() / ELEMENTS); } cannam@148: cannam@148: inline kj::ArrayPtr getRawBytes() { return _reader.asRawBytes(); } cannam@148: cannam@148: Equality equals(AnyList::Reader right); cannam@148: bool operator==(AnyList::Reader right); cannam@148: inline bool operator!=(AnyList::Reader right) { cannam@148: return !(*this == right); cannam@148: } cannam@148: cannam@148: template ReaderFor as() { cannam@148: // T must be List. cannam@148: return ReaderFor(_reader); cannam@148: } cannam@148: private: cannam@148: _::ListReader _reader; cannam@148: cannam@148: template cannam@148: friend struct _::PointerHelpers; cannam@148: friend class Orphanage; cannam@148: }; cannam@148: cannam@148: class AnyList::Builder { cannam@148: public: cannam@148: typedef AnyList Builds; cannam@148: cannam@148: inline Builder(decltype(nullptr)): _builder(ElementSize::VOID) {} cannam@148: inline Builder(_::ListBuilder builder): _builder(builder) {} cannam@148: cannam@148: #if !_MSC_VER // TODO(msvc): MSVC ICEs on this. Try restoring when compiler improves. cannam@148: template ) == Kind::LIST>> cannam@148: inline Builder(T&& value) cannam@148: : _builder(_::PointerHelpers>::getInternalBuilder(kj::fwd(value))) {} cannam@148: #endif cannam@148: cannam@148: inline ElementSize getElementSize() { return _builder.getElementSize(); } cannam@148: inline uint size() { return unbound(_builder.size() / ELEMENTS); } cannam@148: cannam@148: Equality equals(AnyList::Reader right); cannam@148: inline bool operator==(AnyList::Reader right) { cannam@148: return asReader() == right; cannam@148: } cannam@148: inline bool operator!=(AnyList::Reader right) { cannam@148: return !(*this == right); cannam@148: } cannam@148: cannam@148: template BuilderFor as() { cannam@148: // T must be List. cannam@148: return BuilderFor(_builder); cannam@148: } cannam@148: cannam@148: inline operator Reader() const { return Reader(_builder.asReader()); } cannam@148: inline Reader asReader() const { return Reader(_builder.asReader()); } cannam@148: cannam@148: private: cannam@148: _::ListBuilder _builder; cannam@148: cannam@148: friend class Orphanage; cannam@148: }; cannam@148: cannam@148: // ======================================================================================= cannam@148: // Pipeline helpers cannam@148: // cannam@148: // These relate to capabilities, but we don't declare them in capability.h because generated code cannam@148: // for structs needs to know about these, even in files that contain no interfaces. cannam@148: cannam@148: #if !CAPNP_LITE cannam@148: cannam@148: struct PipelineOp { cannam@148: // Corresponds to rpc.capnp's PromisedAnswer.Op. cannam@148: cannam@148: enum Type { cannam@148: NOOP, // for convenience cannam@148: cannam@148: GET_POINTER_FIELD cannam@148: cannam@148: // There may be other types in the future... cannam@148: }; cannam@148: cannam@148: Type type; cannam@148: union { cannam@148: uint16_t pointerIndex; // for GET_POINTER_FIELD cannam@148: }; cannam@148: }; cannam@148: cannam@148: class PipelineHook { cannam@148: // Represents a currently-running call, and implements pipelined requests on its result. cannam@148: cannam@148: public: cannam@148: virtual kj::Own addRef() = 0; cannam@148: // Increment this object's reference count. cannam@148: cannam@148: virtual kj::Own getPipelinedCap(kj::ArrayPtr ops) = 0; cannam@148: // Extract a promised Capability from the results. cannam@148: cannam@148: virtual kj::Own getPipelinedCap(kj::Array&& ops); cannam@148: // Version of getPipelinedCap() passing the array by move. May avoid a copy in some cases. cannam@148: // Default implementation just calls the other version. cannam@148: cannam@148: template > cannam@148: static inline kj::Own from(Pipeline&& pipeline); cannam@148: cannam@148: private: cannam@148: template struct FromImpl; cannam@148: }; cannam@148: cannam@148: #endif // !CAPNP_LITE cannam@148: cannam@148: // ======================================================================================= cannam@148: // Inline implementation details cannam@148: cannam@148: inline MessageSize AnyPointer::Reader::targetSize() const { cannam@148: return reader.targetSize().asPublic(); cannam@148: } cannam@148: cannam@148: inline PointerType AnyPointer::Reader::getPointerType() const { cannam@148: return reader.getPointerType(); cannam@148: } cannam@148: cannam@148: template cannam@148: inline ReaderFor AnyPointer::Reader::getAs() const { cannam@148: return _::PointerHelpers::get(reader); cannam@148: } cannam@148: cannam@148: inline MessageSize AnyPointer::Builder::targetSize() const { cannam@148: return asReader().targetSize(); cannam@148: } cannam@148: cannam@148: inline PointerType AnyPointer::Builder::getPointerType() { cannam@148: return builder.getPointerType(); cannam@148: } cannam@148: cannam@148: inline void AnyPointer::Builder::clear() { cannam@148: return builder.clear(); cannam@148: } cannam@148: cannam@148: template cannam@148: inline BuilderFor AnyPointer::Builder::getAs() { cannam@148: return _::PointerHelpers::get(builder); cannam@148: } cannam@148: cannam@148: template cannam@148: inline BuilderFor AnyPointer::Builder::initAs() { cannam@148: return _::PointerHelpers::init(builder); cannam@148: } cannam@148: cannam@148: template cannam@148: inline BuilderFor AnyPointer::Builder::initAs(uint elementCount) { cannam@148: return _::PointerHelpers::init(builder, elementCount); cannam@148: } cannam@148: cannam@148: inline AnyList::Builder AnyPointer::Builder::initAsAnyList( cannam@148: ElementSize elementSize, uint elementCount) { cannam@148: return AnyList::Builder(builder.initList(elementSize, bounded(elementCount) * ELEMENTS)); cannam@148: } cannam@148: cannam@148: inline List::Builder AnyPointer::Builder::initAsListOfAnyStruct( cannam@148: uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) { cannam@148: return List::Builder(builder.initStructList(bounded(elementCount) * ELEMENTS, cannam@148: _::StructSize(bounded(dataWordCount) * WORDS, cannam@148: bounded(pointerCount) * POINTERS))); cannam@148: } cannam@148: cannam@148: inline AnyStruct::Builder AnyPointer::Builder::initAsAnyStruct( cannam@148: uint16_t dataWordCount, uint16_t pointerCount) { cannam@148: return AnyStruct::Builder(builder.initStruct( cannam@148: _::StructSize(bounded(dataWordCount) * WORDS, cannam@148: bounded(pointerCount) * POINTERS))); cannam@148: } cannam@148: cannam@148: template cannam@148: inline void AnyPointer::Builder::setAs(ReaderFor value) { cannam@148: return _::PointerHelpers::set(builder, value); cannam@148: } cannam@148: cannam@148: template cannam@148: inline void AnyPointer::Builder::setCanonicalAs(ReaderFor value) { cannam@148: return _::PointerHelpers::setCanonical(builder, value); cannam@148: } cannam@148: cannam@148: template cannam@148: inline void AnyPointer::Builder::setAs( cannam@148: std::initializer_list>> list) { cannam@148: return _::PointerHelpers::set(builder, list); cannam@148: } cannam@148: cannam@148: template cannam@148: inline void AnyPointer::Builder::adopt(Orphan&& orphan) { cannam@148: _::PointerHelpers::adopt(builder, kj::mv(orphan)); cannam@148: } cannam@148: cannam@148: template cannam@148: inline Orphan AnyPointer::Builder::disownAs() { cannam@148: return _::PointerHelpers::disown(builder); cannam@148: } cannam@148: cannam@148: inline Orphan AnyPointer::Builder::disown() { cannam@148: return Orphan(builder.disown()); cannam@148: } cannam@148: cannam@148: template <> struct ReaderFor_ { typedef AnyPointer::Reader Type; }; cannam@148: template <> struct BuilderFor_ { typedef AnyPointer::Builder Type; }; cannam@148: template <> struct ReaderFor_ { typedef AnyStruct::Reader Type; }; cannam@148: template <> struct BuilderFor_ { typedef AnyStruct::Builder Type; }; cannam@148: cannam@148: template <> cannam@148: struct Orphanage::GetInnerReader { cannam@148: static inline _::PointerReader apply(const AnyPointer::Reader& t) { cannam@148: return t.reader; cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct Orphanage::GetInnerBuilder { cannam@148: static inline _::PointerBuilder apply(AnyPointer::Builder& t) { cannam@148: return t.builder; cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct Orphanage::GetInnerReader { cannam@148: static inline _::StructReader apply(const AnyStruct::Reader& t) { cannam@148: return t._reader; cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct Orphanage::GetInnerBuilder { cannam@148: static inline _::StructBuilder apply(AnyStruct::Builder& t) { cannam@148: return t._builder; cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct Orphanage::GetInnerReader { cannam@148: static inline _::ListReader apply(const AnyList::Reader& t) { cannam@148: return t._reader; cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct Orphanage::GetInnerBuilder { cannam@148: static inline _::ListBuilder apply(AnyList::Builder& t) { cannam@148: return t._builder; cannam@148: } cannam@148: }; cannam@148: cannam@148: template cannam@148: inline BuilderFor Orphan::getAs() { cannam@148: return _::OrphanGetImpl::apply(builder); cannam@148: } cannam@148: template cannam@148: inline ReaderFor Orphan::getAsReader() const { cannam@148: return _::OrphanGetImpl::applyReader(builder); cannam@148: } cannam@148: template cannam@148: inline Orphan Orphan::releaseAs() { cannam@148: return Orphan(kj::mv(builder)); cannam@148: } cannam@148: cannam@148: // Using AnyPointer as the template type should work... cannam@148: cannam@148: template <> cannam@148: inline typename AnyPointer::Reader AnyPointer::Reader::getAs() const { cannam@148: return *this; cannam@148: } cannam@148: template <> cannam@148: inline typename AnyPointer::Builder AnyPointer::Builder::getAs() { cannam@148: return *this; cannam@148: } cannam@148: template <> cannam@148: inline typename AnyPointer::Builder AnyPointer::Builder::initAs() { cannam@148: clear(); cannam@148: return *this; cannam@148: } cannam@148: template <> cannam@148: inline void AnyPointer::Builder::setAs(AnyPointer::Reader value) { cannam@148: return builder.copyFrom(value.reader); cannam@148: } cannam@148: template <> cannam@148: inline void AnyPointer::Builder::adopt(Orphan&& orphan) { cannam@148: builder.adopt(kj::mv(orphan.builder)); cannam@148: } cannam@148: template <> cannam@148: inline Orphan AnyPointer::Builder::disownAs() { cannam@148: return Orphan(builder.disown()); cannam@148: } cannam@148: template <> cannam@148: inline Orphan Orphan::releaseAs() { cannam@148: return kj::mv(*this); cannam@148: } cannam@148: cannam@148: namespace _ { // private cannam@148: cannam@148: // Specialize PointerHelpers for AnyPointer. cannam@148: cannam@148: template <> cannam@148: struct PointerHelpers { cannam@148: static inline AnyPointer::Reader get(PointerReader reader, cannam@148: const void* defaultValue = nullptr, cannam@148: uint defaultBytes = 0) { cannam@148: return AnyPointer::Reader(reader); cannam@148: } cannam@148: static inline AnyPointer::Builder get(PointerBuilder builder, cannam@148: const void* defaultValue = nullptr, cannam@148: uint defaultBytes = 0) { cannam@148: return AnyPointer::Builder(builder); cannam@148: } cannam@148: static inline void set(PointerBuilder builder, AnyPointer::Reader value) { cannam@148: AnyPointer::Builder(builder).set(value); cannam@148: } cannam@148: static inline void adopt(PointerBuilder builder, Orphan&& value) { cannam@148: builder.adopt(kj::mv(value.builder)); cannam@148: } cannam@148: static inline Orphan disown(PointerBuilder builder) { cannam@148: return Orphan(builder.disown()); cannam@148: } cannam@148: static inline _::PointerReader getInternalReader(const AnyPointer::Reader& reader) { cannam@148: return reader.reader; cannam@148: } cannam@148: static inline _::PointerBuilder getInternalBuilder(AnyPointer::Builder&& builder) { cannam@148: return builder.builder; cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct PointerHelpers { cannam@148: static inline AnyStruct::Reader get( cannam@148: PointerReader reader, const word* defaultValue = nullptr) { cannam@148: return AnyStruct::Reader(reader.getStruct(defaultValue)); cannam@148: } cannam@148: static inline AnyStruct::Builder get( cannam@148: PointerBuilder builder, const word* defaultValue = nullptr) { cannam@148: // TODO(someday): Allow specifying the size somehow? cannam@148: return AnyStruct::Builder(builder.getStruct( cannam@148: _::StructSize(ZERO * WORDS, ZERO * POINTERS), defaultValue)); cannam@148: } cannam@148: static inline void set(PointerBuilder builder, AnyStruct::Reader value) { cannam@148: builder.setStruct(value._reader); cannam@148: } cannam@148: static inline AnyStruct::Builder init( cannam@148: PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount) { cannam@148: return AnyStruct::Builder(builder.initStruct( cannam@148: StructSize(bounded(dataWordCount) * WORDS, cannam@148: bounded(pointerCount) * POINTERS))); cannam@148: } cannam@148: cannam@148: static void adopt(PointerBuilder builder, Orphan&& value) { cannam@148: builder.adopt(kj::mv(value.builder)); cannam@148: } cannam@148: static Orphan disown(PointerBuilder builder) { cannam@148: return Orphan(builder.disown()); cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct PointerHelpers { cannam@148: static inline AnyList::Reader get( cannam@148: PointerReader reader, const word* defaultValue = nullptr) { cannam@148: return AnyList::Reader(reader.getListAnySize(defaultValue)); cannam@148: } cannam@148: static inline AnyList::Builder get( cannam@148: PointerBuilder builder, const word* defaultValue = nullptr) { cannam@148: return AnyList::Builder(builder.getListAnySize(defaultValue)); cannam@148: } cannam@148: static inline void set(PointerBuilder builder, AnyList::Reader value) { cannam@148: builder.setList(value._reader); cannam@148: } cannam@148: static inline AnyList::Builder init( cannam@148: PointerBuilder builder, ElementSize elementSize, uint elementCount) { cannam@148: return AnyList::Builder(builder.initList( cannam@148: elementSize, bounded(elementCount) * ELEMENTS)); cannam@148: } cannam@148: static inline AnyList::Builder init( cannam@148: PointerBuilder builder, uint16_t dataWordCount, uint16_t pointerCount, uint elementCount) { cannam@148: return AnyList::Builder(builder.initStructList( cannam@148: bounded(elementCount) * ELEMENTS, cannam@148: StructSize(bounded(dataWordCount) * WORDS, cannam@148: bounded(pointerCount) * POINTERS))); cannam@148: } cannam@148: cannam@148: static void adopt(PointerBuilder builder, Orphan&& value) { cannam@148: builder.adopt(kj::mv(value.builder)); cannam@148: } cannam@148: static Orphan disown(PointerBuilder builder) { cannam@148: return Orphan(builder.disown()); cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct OrphanGetImpl { cannam@148: static inline AnyStruct::Builder apply(_::OrphanBuilder& builder) { cannam@148: return AnyStruct::Builder(builder.asStruct(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); cannam@148: } cannam@148: static inline AnyStruct::Reader applyReader(const _::OrphanBuilder& builder) { cannam@148: return AnyStruct::Reader(builder.asStructReader(_::StructSize(ZERO * WORDS, ZERO * POINTERS))); cannam@148: } cannam@148: static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { cannam@148: builder.truncate(size, _::StructSize(ZERO * WORDS, ZERO * POINTERS)); cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct OrphanGetImpl { cannam@148: static inline AnyList::Builder apply(_::OrphanBuilder& builder) { cannam@148: return AnyList::Builder(builder.asListAnySize()); cannam@148: } cannam@148: static inline AnyList::Reader applyReader(const _::OrphanBuilder& builder) { cannam@148: return AnyList::Reader(builder.asListReaderAnySize()); cannam@148: } cannam@148: static inline void truncateListOf(_::OrphanBuilder& builder, ElementCount size) { cannam@148: builder.truncate(size, ElementSize::POINTER); cannam@148: } cannam@148: }; cannam@148: cannam@148: } // namespace _ (private) cannam@148: cannam@148: #if !CAPNP_LITE cannam@148: cannam@148: template cannam@148: struct PipelineHook::FromImpl { cannam@148: static inline kj::Own apply(typename T::Pipeline&& pipeline) { cannam@148: return from(kj::mv(pipeline._typeless)); cannam@148: } cannam@148: }; cannam@148: cannam@148: template <> cannam@148: struct PipelineHook::FromImpl { cannam@148: static inline kj::Own apply(AnyPointer::Pipeline&& pipeline) { cannam@148: return kj::mv(pipeline.hook); cannam@148: } cannam@148: }; cannam@148: cannam@148: template cannam@148: inline kj::Own PipelineHook::from(Pipeline&& pipeline) { cannam@148: return FromImpl::apply(kj::fwd(pipeline)); cannam@148: } cannam@148: cannam@148: #endif // !CAPNP_LITE cannam@148: cannam@148: } // namespace capnp cannam@148: cannam@148: #endif // CAPNP_ANY_H_