Mercurial > hg > sv-dependency-builds
diff osx/include/capnp/dynamic.h @ 147:45360b968bf4
Cap'n Proto v0.6 + build for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Mon, 22 May 2017 10:01:37 +0100 |
parents | 41e769c91eca |
children |
line wrap: on
line diff
--- 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<DynamicValue>; - -template <Kind k> struct DynamicTypeFor_; -template <> struct DynamicTypeFor_<Kind::ENUM> { typedef DynamicEnum Type; }; -template <> struct DynamicTypeFor_<Kind::STRUCT> { typedef DynamicStruct Type; }; -template <> struct DynamicTypeFor_<Kind::LIST> { typedef DynamicList Type; }; -template <> struct DynamicTypeFor_<Kind::INTERFACE> { typedef DynamicCapability Type; }; - -template <typename T> -using DynamicTypeFor = typename DynamicTypeFor_<kind<T>()>::Type; - -template <typename T> -ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value); -template <typename T> -BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value); -template <typename T> -DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value); -template <typename T> -typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value); - -namespace _ { // private - -template <> struct Kind_<DynamicValue > { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_<DynamicEnum > { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_<DynamicStruct > { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_<DynamicList > { static constexpr Kind kind = Kind::OTHER; }; -template <> struct Kind_<DynamicCapability> { static constexpr Kind kind = Kind::OTHER; }; - -} // namespace _ (private) - -template <> inline constexpr Style style<DynamicValue >() { return Style::POINTER; } -template <> inline constexpr Style style<DynamicEnum >() { return Style::PRIMITIVE; } -template <> inline constexpr Style style<DynamicStruct >() { return Style::STRUCT; } -template <> inline constexpr Style style<DynamicList >() { return Style::POINTER; } -template <> inline constexpr Style style<DynamicCapability>() { 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 <typename T, typename = kj::EnableIf<kind<T>() == Kind::ENUM>> - inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {} - - template <typename T> - inline T as() const { return static_cast<T>(asImpl(typeId<T>())); } - // Cast to a native enum type. - - inline EnumSchema getSchema() const { return schema; } - - kj::Maybe<EnumSchema::Enumerant> 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 <typename T> - friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value); -}; - -// ------------------------------------------------------------------- - -class DynamicStruct::Reader { -public: - typedef DynamicStruct Reads; - - Reader() = default; - - template <typename T, typename = kj::EnableIf<kind<FromReader<T>>() == Kind::STRUCT>> - inline Reader(T&& value): Reader(toDynamic(value)) {} - - inline MessageSize totalSize() const { return reader.totalSize().asPublic(); } - - template <typename T> - 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<StructSchema::Field> 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 <typename T, Kind K> - friend struct _::PointerHelpers; - friend class DynamicStruct::Builder; - friend struct DynamicList; - friend class MessageReader; - friend class MessageBuilder; - template <typename T, ::capnp::Kind k> - friend struct ::capnp::ToDynamic_; - friend kj::StringTree _::structString( - _::StructReader reader, const _::RawBrandedSchema& schema); - friend class Orphanage; - friend class Orphan<DynamicStruct>; - friend class Orphan<DynamicValue>; - friend class Orphan<AnyPointer>; -}; - -class DynamicStruct::Builder { -public: - typedef DynamicStruct Builds; - - Builder() = default; - inline Builder(decltype(nullptr)) {} - - template <typename T, typename = kj::EnableIf<kind<FromBuilder<T>>() == Kind::STRUCT>> - inline Builder(T&& value): Builder(toDynamic(value)) {} - - inline MessageSize totalSize() const { return asReader().totalSize(); } - - template <typename T> - 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<StructSchema::Field> 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<DynamicValue>&& orphan); - Orphan<DynamicValue> 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<DynamicValue::Reader> value); - DynamicValue::Builder init(kj::StringPtr name); - DynamicValue::Builder init(kj::StringPtr name, uint size); - void adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan); - Orphan<DynamicValue> 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 <typename T, Kind k> - friend struct _::PointerHelpers; - friend struct DynamicList; - friend class MessageReader; - friend class MessageBuilder; - template <typename T, ::capnp::Kind k> - friend struct ::capnp::ToDynamic_; - friend class Orphanage; - friend class Orphan<DynamicStruct>; - friend class Orphan<DynamicValue>; - friend class Orphan<AnyPointer>; -}; - -class DynamicStruct::Pipeline { -public: - typedef DynamicStruct Pipelines; - - inline Pipeline(decltype(nullptr)): typeless(nullptr) {} - - template <typename T> - 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<DynamicStruct, DynamicStruct>; -}; - -// ------------------------------------------------------------------- - -class DynamicList::Reader { -public: - typedef DynamicList Reads; - - inline Reader(): reader(ElementSize::VOID) {} - - template <typename T, typename = kj::EnableIf<kind<FromReader<T>>() == Kind::LIST>> - inline Reader(T&& value): Reader(toDynamic(value)) {} - - template <typename T> - typename T::Reader as() const; - // Try to convert to any List<T>, 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<const Reader, DynamicValue::Reader> 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 <typename T, Kind k> - friend struct _::PointerHelpers; - friend struct DynamicStruct; - friend class DynamicList::Builder; - template <typename T, ::capnp::Kind k> - friend struct ::capnp::ToDynamic_; - friend class Orphanage; - friend class Orphan<DynamicList>; - friend class Orphan<DynamicValue>; - friend class Orphan<AnyPointer>; -}; - -class DynamicList::Builder { -public: - typedef DynamicList Builds; - - inline Builder(): builder(ElementSize::VOID) {} - inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {} - - template <typename T, typename = kj::EnableIf<kind<FromBuilder<T>>() == Kind::LIST>> - inline Builder(T&& value): Builder(toDynamic(value)) {} - - template <typename T> - typename T::Builder as(); - // Try to convert to any List<T>, 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<DynamicValue>&& orphan); - Orphan<DynamicValue> disown(uint index); - - typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator; - inline Iterator begin() { return Iterator(this, 0); } - inline Iterator end() { return Iterator(this, size()); } - - void copyFrom(std::initializer_list<DynamicValue::Reader> value); - - Reader asReader() const; - -private: - ListSchema schema; - _::ListBuilder builder; - - Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {} - - template <typename T, Kind k> - friend struct _::PointerHelpers; - friend struct DynamicStruct; - template <typename T, ::capnp::Kind k> - friend struct ::capnp::ToDynamic_; - friend class Orphanage; - template <typename T, Kind k> - friend struct _::OrphanGetImpl; - friend class Orphan<DynamicList>; - friend class Orphan<DynamicValue>; - friend class Orphan<AnyPointer>; -}; - -// ------------------------------------------------------------------- - -class DynamicCapability::Client: public Capability::Client { -public: - typedef DynamicCapability Calls; - typedef DynamicCapability Reads; - - Client() = default; - - template <typename T, typename = kj::EnableIf<kind<FromClient<T>>() == Kind::INTERFACE>> - inline Client(T&& client); - - template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>> - inline Client(kj::Own<T>&& server); - - template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>> - typename T::Client as(); - template <typename T, typename = kj::EnableIf<kind<T>() == 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<DynamicStruct, DynamicStruct> newRequest( - InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr); - Request<DynamicStruct, DynamicStruct> newRequest( - kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr); - -private: - InterfaceSchema schema; - - Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook) - : Capability::Client(kj::mv(hook)), schema(schema) {} - - template <typename T> - inline Client(InterfaceSchema schema, kj::Own<T>&& server); - - friend struct Capability; - friend struct DynamicStruct; - friend struct DynamicList; - friend struct DynamicValue; - friend class Orphan<DynamicCapability>; - friend class Orphan<DynamicValue>; - friend class Orphan<AnyPointer>; - template <typename T, Kind k> - friend struct _::PointerHelpers; -}; - -class DynamicCapability::Server: public Capability::Server { -public: - typedef DynamicCapability Serves; - - Server(InterfaceSchema schema): schema(schema) {} - - virtual kj::Promise<void> call(InterfaceSchema::Method method, - CallContext<DynamicStruct, DynamicStruct> context) = 0; - - kj::Promise<void> dispatchCall(uint64_t interfaceId, uint16_t methodId, - CallContext<AnyPointer, AnyPointer> context) override final; - - inline InterfaceSchema getSchema() const { return schema; } - -private: - InterfaceSchema schema; -}; - -template <> -class Request<DynamicStruct, DynamicStruct>: public DynamicStruct::Builder { - // Specialization of `Request<T, U>` for DynamicStruct. - -public: - inline Request(DynamicStruct::Builder builder, kj::Own<RequestHook>&& hook, - StructSchema resultSchema) - : DynamicStruct::Builder(builder), hook(kj::mv(hook)), resultSchema(resultSchema) {} - - RemotePromise<DynamicStruct> send(); - // Send the call and return a promise for the results. - -private: - kj::Own<RequestHook> hook; - StructSchema resultSchema; - - friend class Capability::Client; - friend struct DynamicCapability; - template <typename, typename> - friend class CallContext; - friend class RequestHook; -}; - -template <> -class CallContext<DynamicStruct, DynamicStruct>: 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<MessageSize> sizeHint = nullptr); - DynamicStruct::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr); - void setResults(DynamicStruct::Reader value); - void adoptResults(Orphan<DynamicStruct>&& value); - Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr); - template <typename SubParams> - kj::Promise<void> tailCall(Request<SubParams, DynamicStruct>&& tailRequest); - void allowCancellation(); - -private: - CallContextHook* hook; - StructSchema paramType; - StructSchema resultType; - - friend class DynamicCapability::Server; -}; - -// ------------------------------------------------------------------- - -// Make sure ReaderFor<T> and BuilderFor<T> work for DynamicEnum, DynamicStruct, and -// DynamicList, so that we can define DynamicValue::as(). - -template <> struct ReaderFor_ <DynamicEnum, Kind::OTHER> { typedef DynamicEnum Type; }; -template <> struct BuilderFor_<DynamicEnum, Kind::OTHER> { typedef DynamicEnum Type; }; -template <> struct ReaderFor_ <DynamicStruct, Kind::OTHER> { typedef DynamicStruct::Reader Type; }; -template <> struct BuilderFor_<DynamicStruct, Kind::OTHER> { typedef DynamicStruct::Builder Type; }; -template <> struct ReaderFor_ <DynamicList, Kind::OTHER> { typedef DynamicList::Reader Type; }; -template <> struct BuilderFor_<DynamicList, Kind::OTHER> { typedef DynamicList::Builder Type; }; -template <> struct ReaderFor_ <DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; }; -template <> struct BuilderFor_<DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; }; -template <> struct PipelineFor_<DynamicCapability, Kind::OTHER> { 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 <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>> - inline Reader(kj::Own<T>&& value); - Reader(ConstSchema constant); - - template <typename T, typename = decltype(toDynamic(kj::instance<T>()))> - 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 <typename T> - inline ReaderFor<T> as() const { return AsImpl<T>::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<T> for any T listed above: Returns List<T>::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 <typename T, Kind kind = kind<T>()> 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 <typename T, typename = decltype(toDynamic(kj::instance<T>()))> - 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 <typename T> - inline BuilderFor<T> as() { return AsImpl<T>::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 <typename T, Kind kind = kind<T>()> 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<DynamicValue>; -}; - -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 <typename T> - inline PipelineFor<T> releaseAs() { return AsImpl<T>::apply(*this); } - - inline Type getType() { return type; } - // Get the type of this value. - -private: - Type type; - union { - DynamicStruct::Pipeline structValue; - DynamicCapability::Client capabilityValue; - }; - - template <typename T, Kind kind = kind<T>()> 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<DynamicStruct> { -public: - Orphan() = default; - KJ_DISALLOW_COPY(Orphan); - Orphan(Orphan&&) = default; - Orphan& operator=(Orphan&&) = default; - - template <typename T, typename = kj::EnableIf<kind<T>() == Kind::STRUCT>> - inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {} - - DynamicStruct::Builder get(); - DynamicStruct::Reader getReader() const; - - template <typename T> - Orphan<T> releaseAs(); - // Like DynamicStruct::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, - // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is - // transferred to the returned Orphan<T>. - - 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 <typename, Kind> - friend struct _::PointerHelpers; - friend struct DynamicList; - friend class Orphanage; - friend class Orphan<DynamicValue>; - friend class Orphan<AnyPointer>; - friend class MessageBuilder; -}; - -template <> -class Orphan<DynamicList> { -public: - Orphan() = default; - KJ_DISALLOW_COPY(Orphan); - Orphan(Orphan&&) = default; - Orphan& operator=(Orphan&&) = default; - - template <typename T, typename = kj::EnableIf<kind<T>() == Kind::LIST>> - inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {} - - DynamicList::Builder get(); - DynamicList::Reader getReader() const; - - template <typename T> - Orphan<T> releaseAs(); - // Like DynamicList::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, - // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is - // transferred to the returned Orphan<T>. - - // 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 <typename, Kind> - friend struct _::PointerHelpers; - friend struct DynamicList; - friend class Orphanage; - friend class Orphan<DynamicValue>; - friend class Orphan<AnyPointer>; -}; - -template <> -class Orphan<DynamicCapability> { -public: - Orphan() = default; - KJ_DISALLOW_COPY(Orphan); - Orphan(Orphan&&) = default; - Orphan& operator=(Orphan&&) = default; - - template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>> - inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {} - - DynamicCapability::Client get(); - DynamicCapability::Client getReader() const; - - template <typename T> - Orphan<T> releaseAs(); - // Like DynamicCapability::Client::as(), but coerces the Orphan type. Since Orphans are move-only, - // the original Orphan<DynamicCapability> is no longer valid after this call; ownership is - // transferred to the returned Orphan<T>. - - 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 <typename, Kind> - friend struct _::PointerHelpers; - friend struct DynamicList; - friend class Orphanage; - friend class Orphan<DynamicValue>; - friend class Orphan<AnyPointer>; -}; - -template <> -class Orphan<DynamicValue> { -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 <typename T> - Orphan(Orphan<T>&&); - Orphan(Orphan<AnyPointer>&&); - 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 <typename T> - Orphan<T> releaseAs(); - // Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, - // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is - // transferred to the returned Orphan<T>. - -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 <typename, Kind> - friend struct _::PointerHelpers; - friend struct DynamicStruct; - friend struct DynamicList; - friend struct AnyPointer; - friend class Orphanage; -}; - -template <typename T> -inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other) - : Orphan(other.get(), kj::mv(other.builder)) {} - -inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other) - : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {} - -template <typename T> -Orphan<T> Orphan<DynamicStruct>::releaseAs() { - get().as<T>(); // type check - return Orphan<T>(kj::mv(builder)); -} - -template <typename T> -Orphan<T> Orphan<DynamicList>::releaseAs() { - get().as<T>(); // type check - return Orphan<T>(kj::mv(builder)); -} - -template <typename T> -Orphan<T> Orphan<DynamicCapability>::releaseAs() { - get().as<T>(); // type check - return Orphan<T>(kj::mv(builder)); -} - -template <typename T> -Orphan<T> Orphan<DynamicValue>::releaseAs() { - get().as<T>(); // type check - type = DynamicValue::UNKNOWN; - return Orphan<T>(kj::mv(builder)); -} - -template <> -Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>(); -template <> -Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>(); -template <> -Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>(); -template <> -Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>(); - -template <> -struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::OTHER> { - static inline _::StructBuilder apply(DynamicStruct::Builder& t) { - return t.builder; - } -}; - -template <> -struct Orphanage::GetInnerBuilder<DynamicList, Kind::OTHER> { - static inline _::ListBuilder apply(DynamicList::Builder& t) { - return t.builder; - } -}; - -template <> -inline Orphan<DynamicStruct> Orphanage::newOrphanCopy<DynamicStruct::Reader>( - DynamicStruct::Reader copyFrom) const { - return Orphan<DynamicStruct>( - copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); -} - -template <> -inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>( - DynamicList::Reader copyFrom) const { - return Orphan<DynamicList>(copyFrom.getSchema(), - _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); -} - -template <> -inline Orphan<DynamicCapability> Orphanage::newOrphanCopy<DynamicCapability::Client>( - DynamicCapability::Client copyFrom) const { - return Orphan<DynamicCapability>( - copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef())); -} - -template <> -Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>( - DynamicValue::Reader copyFrom) const; - -namespace _ { // private - -template <> -struct PointerHelpers<DynamicStruct, Kind::OTHER> { - // 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<DynamicStruct>&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan<DynamicStruct> disown(PointerBuilder builder, StructSchema schema) { - return Orphan<DynamicStruct>(schema, builder.disown()); - } -}; - -template <> -struct PointerHelpers<DynamicList, Kind::OTHER> { - // 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<DynamicList>&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan<DynamicList> disown(PointerBuilder builder, ListSchema schema) { - return Orphan<DynamicList>(schema, builder.disown()); - } -}; - -template <> -struct PointerHelpers<DynamicCapability, Kind::OTHER> { - // 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<DynamicCapability>&& value) { - builder.adopt(kj::mv(value.builder)); - } - static inline Orphan<DynamicCapability> disown(PointerBuilder builder, InterfaceSchema schema) { - return Orphan<DynamicCapability>(schema, builder.disown()); - } -}; - -} // namespace _ (private) - -template <typename T> -inline ReaderFor<T> AnyPointer::Reader::getAs(StructSchema schema) const { - return _::PointerHelpers<T>::getDynamic(reader, schema); -} -template <typename T> -inline ReaderFor<T> AnyPointer::Reader::getAs(ListSchema schema) const { - return _::PointerHelpers<T>::getDynamic(reader, schema); -} -template <typename T> -inline ReaderFor<T> AnyPointer::Reader::getAs(InterfaceSchema schema) const { - return _::PointerHelpers<T>::getDynamic(reader, schema); -} -template <typename T> -inline BuilderFor<T> AnyPointer::Builder::getAs(StructSchema schema) { - return _::PointerHelpers<T>::getDynamic(builder, schema); -} -template <typename T> -inline BuilderFor<T> AnyPointer::Builder::getAs(ListSchema schema) { - return _::PointerHelpers<T>::getDynamic(builder, schema); -} -template <typename T> -inline BuilderFor<T> AnyPointer::Builder::getAs(InterfaceSchema schema) { - return _::PointerHelpers<T>::getDynamic(builder, schema); -} -template <typename T> -inline BuilderFor<T> AnyPointer::Builder::initAs(StructSchema schema) { - return _::PointerHelpers<T>::init(builder, schema); -} -template <typename T> -inline BuilderFor<T> AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) { - return _::PointerHelpers<T>::init(builder, schema, elementCount); -} -template <> -inline void AnyPointer::Builder::setAs<DynamicStruct>(DynamicStruct::Reader value) { - return _::PointerHelpers<DynamicStruct>::set(builder, value); -} -template <> -inline void AnyPointer::Builder::setAs<DynamicList>(DynamicList::Reader value) { - return _::PointerHelpers<DynamicList>::set(builder, value); -} -template <> -inline void AnyPointer::Builder::setAs<DynamicCapability>(DynamicCapability::Client value) { - return _::PointerHelpers<DynamicCapability>::set(builder, kj::mv(value)); -} -template <> -void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan); -template <typename T> -inline Orphan<T> AnyPointer::Builder::disownAs(StructSchema schema) { - return _::PointerHelpers<T>::disown(builder, schema); -} -template <typename T> -inline Orphan<T> AnyPointer::Builder::disownAs(ListSchema schema) { - return _::PointerHelpers<T>::disown(builder, schema); -} -template <typename T> -inline Orphan<T> AnyPointer::Builder::disownAs(InterfaceSchema schema) { - return _::PointerHelpers<T>::disown(builder, schema); -} - -template <> -DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema); -template <> -DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema); -template <> -DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(InterfaceSchema schema); -template <> -DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(StructSchema schema) const; -template <> -DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const; -template <> -DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>( - InterfaceSchema schema) const; -template <> -Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema); -template <> -Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema); -template <> -Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>( - InterfaceSchema schema); - -// ======================================================================================= -// Inline implementation details. - -template <typename T> -struct ToDynamic_<T, Kind::STRUCT> { - static inline DynamicStruct::Reader apply(const typename T::Reader& value) { - return DynamicStruct::Reader(Schema::from<T>(), value._reader); - } - static inline DynamicStruct::Builder apply(typename T::Builder& value) { - return DynamicStruct::Builder(Schema::from<T>(), value._builder); - } -}; - -template <typename T> -struct ToDynamic_<T, Kind::LIST> { - static inline DynamicList::Reader apply(const typename T::Reader& value) { - return DynamicList::Reader(Schema::from<T>(), value.reader); - } - static inline DynamicList::Builder apply(typename T::Builder& value) { - return DynamicList::Builder(Schema::from<T>(), value.builder); - } -}; - -template <typename T> -struct ToDynamic_<T, Kind::INTERFACE> { - 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 <typename T> -ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) { - return ToDynamic_<FromReader<T>>::apply(value); -} -template <typename T> -BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) { - return ToDynamic_<FromBuilder<T>>::apply(value); -} -template <typename T> -DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) { - return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value)); -} -template <typename T> -typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) { - return typename FromServer<T>::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<DynamicValue>::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 <typename T, typename> -inline DynamicValue::Reader::Reader(kj::Own<T>&& 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<typeName> { \ - static ReaderFor<typeName> apply(const Reader& reader); \ -}; \ -template <> \ -struct DynamicValue::Builder::AsImpl<typeName> { \ - static BuilderFor<typeName> 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<Void> { - static Void apply(const Reader& reader); -}; -template <> -struct DynamicValue::Builder::AsImpl<Void> { - static Void apply(Builder& builder); -}; - -template <typename T> -struct DynamicValue::Reader::AsImpl<T, Kind::ENUM> { - static T apply(const Reader& reader) { - return reader.as<DynamicEnum>().as<T>(); - } -}; -template <typename T> -struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> { - static T apply(Builder& builder) { - return builder.as<DynamicEnum>().as<T>(); - } -}; - -template <typename T> -struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> { - static typename T::Reader apply(const Reader& reader) { - return reader.as<DynamicStruct>().as<T>(); - } -}; -template <typename T> -struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> { - static typename T::Builder apply(Builder& builder) { - return builder.as<DynamicStruct>().as<T>(); - } -}; - -template <typename T> -struct DynamicValue::Reader::AsImpl<T, Kind::LIST> { - static typename T::Reader apply(const Reader& reader) { - return reader.as<DynamicList>().as<T>(); - } -}; -template <typename T> -struct DynamicValue::Builder::AsImpl<T, Kind::LIST> { - static typename T::Builder apply(Builder& builder) { - return builder.as<DynamicList>().as<T>(); - } -}; - -template <typename T> -struct DynamicValue::Reader::AsImpl<T, Kind::INTERFACE> { - static typename T::Client apply(const Reader& reader) { - return reader.as<DynamicCapability>().as<T>(); - } -}; -template <typename T> -struct DynamicValue::Builder::AsImpl<T, Kind::INTERFACE> { - static typename T::Client apply(Builder& builder) { - return builder.as<DynamicCapability>().as<T>(); - } -}; - -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 <typename T> -struct DynamicValue::Pipeline::AsImpl<T, Kind::STRUCT> { - static typename T::Pipeline apply(Pipeline& pipeline) { - return pipeline.releaseAs<DynamicStruct>().releaseAs<T>(); - } -}; -template <typename T> -struct DynamicValue::Pipeline::AsImpl<T, Kind::INTERFACE> { - static typename T::Client apply(Pipeline& pipeline) { - return pipeline.releaseAs<DynamicCapability>().releaseAs<T>(); - } -}; -template <> -struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> { - static PipelineFor<DynamicStruct> apply(Pipeline& pipeline); -}; -template <> -struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> { - static PipelineFor<DynamicCapability> apply(Pipeline& pipeline); -}; - -// ------------------------------------------------------------------- - -template <typename T> -typename T::Reader DynamicStruct::Reader::as() const { - static_assert(kind<T>() == Kind::STRUCT, - "DynamicStruct::Reader::as<T>() can only convert to struct types."); - schema.requireUsableAs<T>(); - return typename T::Reader(reader); -} - -template <typename T> -typename T::Builder DynamicStruct::Builder::as() { - static_assert(kind<T>() == Kind::STRUCT, - "DynamicStruct::Builder::as<T>() can only convert to struct types."); - schema.requireUsableAs<T>(); - return typename T::Builder(builder); -} - -template <> -inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const { - return *this; -} -template <> -inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() { - return *this; -} - -inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const { - return DynamicStruct::Reader(schema, builder.asReader()); -} - -template <> -inline AnyStruct::Reader DynamicStruct::Reader::as<AnyStruct>() const { - return AnyStruct::Reader(reader); -} - -template <> -inline AnyStruct::Builder DynamicStruct::Builder::as<AnyStruct>() { - return AnyStruct::Builder(builder); -} - -template <typename T> -typename T::Pipeline DynamicStruct::Pipeline::releaseAs() { - static_assert(kind<T>() == Kind::STRUCT, - "DynamicStruct::Pipeline::releaseAs<T>() can only convert to struct types."); - schema.requireUsableAs<T>(); - return typename T::Pipeline(kj::mv(typeless)); -} - -// ------------------------------------------------------------------- - -template <typename T> -typename T::Reader DynamicList::Reader::as() const { - static_assert(kind<T>() == Kind::LIST, - "DynamicStruct::Reader::as<T>() can only convert to list types."); - schema.requireUsableAs<T>(); - return typename T::Reader(reader); -} -template <typename T> -typename T::Builder DynamicList::Builder::as() { - static_assert(kind<T>() == Kind::LIST, - "DynamicStruct::Builder::as<T>() can only convert to list types."); - schema.requireUsableAs<T>(); - return typename T::Builder(builder); -} - -template <> -inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const { - return *this; -} -template <> -inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() { - return *this; -} - -// ------------------------------------------------------------------- - -template <typename T, typename> -inline DynamicCapability::Client::Client(T&& client) - : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {} - -template <typename T, typename> -inline DynamicCapability::Client::Client(kj::Own<T>&& server) - : Client(server->getSchema(), kj::mv(server)) {} -template <typename T> -inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server) - : Capability::Client(kj::mv(server)), schema(schema) {} - -template <typename T, typename> -typename T::Client DynamicCapability::Client::as() { - static_assert(kind<T>() == Kind::INTERFACE, - "DynamicCapability::Client::as<T>() can only convert to interface types."); - schema.requireUsableAs<T>(); - return typename T::Client(hook->addRef()); -} - -template <typename T, typename> -typename T::Client DynamicCapability::Client::releaseAs() { - static_assert(kind<T>() == Kind::INTERFACE, - "DynamicCapability::Client::as<T>() can only convert to interface types."); - schema.requireUsableAs<T>(); - return typename T::Client(kj::mv(hook)); -} - -inline CallContext<DynamicStruct, DynamicStruct>::CallContext( - CallContextHook& hook, StructSchema paramType, StructSchema resultType) - : hook(&hook), paramType(paramType), resultType(resultType) {} -inline DynamicStruct::Reader CallContext<DynamicStruct, DynamicStruct>::getParams() { - return hook->getParams().getAs<DynamicStruct>(paramType); -} -inline void CallContext<DynamicStruct, DynamicStruct>::releaseParams() { - hook->releaseParams(); -} -inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::getResults( - kj::Maybe<MessageSize> sizeHint) { - return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType); -} -inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults( - kj::Maybe<MessageSize> sizeHint) { - return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType); -} -inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) { - hook->getResults(value.totalSize()).setAs<DynamicStruct>(value); -} -inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) { - hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value)); -} -inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage( - kj::Maybe<MessageSize> sizeHint) { - return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); -} -template <typename SubParams> -inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall( - Request<SubParams, DynamicStruct>&& tailRequest) { - return hook->tailCall(kj::mv(tailRequest.hook)); -} -inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() { - hook->allowCancellation(); -} - -template <> -inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>( - InterfaceSchema schema) { - return DynamicCapability::Client(schema, hook->addRef()); -} - -// ------------------------------------------------------------------- - -template <typename T> -ReaderFor<T> ConstSchema::as() const { - return DynamicValue::Reader(*this).as<T>(); -} - -} // 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<DynamicValue>; + +template <Kind k> struct DynamicTypeFor_; +template <> struct DynamicTypeFor_<Kind::ENUM> { typedef DynamicEnum Type; }; +template <> struct DynamicTypeFor_<Kind::STRUCT> { typedef DynamicStruct Type; }; +template <> struct DynamicTypeFor_<Kind::LIST> { typedef DynamicList Type; }; +template <> struct DynamicTypeFor_<Kind::INTERFACE> { typedef DynamicCapability Type; }; + +template <typename T> +using DynamicTypeFor = typename DynamicTypeFor_<kind<T>()>::Type; + +template <typename T> +ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value); +template <typename T> +BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value); +template <typename T> +DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value); +template <typename T> +typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value); + +namespace _ { // private + +template <> struct Kind_<DynamicValue > { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_<DynamicEnum > { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_<DynamicStruct > { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_<DynamicList > { static constexpr Kind kind = Kind::OTHER; }; +template <> struct Kind_<DynamicCapability> { static constexpr Kind kind = Kind::OTHER; }; + +} // namespace _ (private) + +template <> inline constexpr Style style<DynamicValue >() { return Style::POINTER; } +template <> inline constexpr Style style<DynamicEnum >() { return Style::PRIMITIVE; } +template <> inline constexpr Style style<DynamicStruct >() { return Style::STRUCT; } +template <> inline constexpr Style style<DynamicList >() { return Style::POINTER; } +template <> inline constexpr Style style<DynamicCapability>() { 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 <typename T, typename = kj::EnableIf<kind<T>() == Kind::ENUM>> + inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {} + + template <typename T> + inline T as() const { return static_cast<T>(asImpl(typeId<T>())); } + // Cast to a native enum type. + + inline EnumSchema getSchema() const { return schema; } + + kj::Maybe<EnumSchema::Enumerant> 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 <typename T> + friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value); +}; + +// ------------------------------------------------------------------- + +class DynamicStruct::Reader { +public: + typedef DynamicStruct Reads; + + Reader() = default; + + template <typename T, typename = kj::EnableIf<kind<FromReader<T>>() == Kind::STRUCT>> + inline Reader(T&& value): Reader(toDynamic(value)) {} + + inline MessageSize totalSize() const { return reader.totalSize().asPublic(); } + + template <typename T> + 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<StructSchema::Field> 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 <typename T, Kind K> + friend struct _::PointerHelpers; + friend class DynamicStruct::Builder; + friend struct DynamicList; + friend class MessageReader; + friend class MessageBuilder; + template <typename T, ::capnp::Kind k> + friend struct ::capnp::ToDynamic_; + friend kj::StringTree _::structString( + _::StructReader reader, const _::RawBrandedSchema& schema); + friend class Orphanage; + friend class Orphan<DynamicStruct>; + friend class Orphan<DynamicValue>; + friend class Orphan<AnyPointer>; +}; + +class DynamicStruct::Builder { +public: + typedef DynamicStruct Builds; + + Builder() = default; + inline Builder(decltype(nullptr)) {} + + template <typename T, typename = kj::EnableIf<kind<FromBuilder<T>>() == Kind::STRUCT>> + inline Builder(T&& value): Builder(toDynamic(value)) {} + + inline MessageSize totalSize() const { return asReader().totalSize(); } + + template <typename T> + 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<StructSchema::Field> 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<DynamicValue>&& orphan); + Orphan<DynamicValue> 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<DynamicValue::Reader> value); + DynamicValue::Builder init(kj::StringPtr name); + DynamicValue::Builder init(kj::StringPtr name, uint size); + void adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan); + Orphan<DynamicValue> 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 <typename T, Kind k> + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class MessageReader; + friend class MessageBuilder; + template <typename T, ::capnp::Kind k> + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + friend class Orphan<DynamicStruct>; + friend class Orphan<DynamicValue>; + friend class Orphan<AnyPointer>; +}; + +class DynamicStruct::Pipeline { +public: + typedef DynamicStruct Pipelines; + + inline Pipeline(decltype(nullptr)): typeless(nullptr) {} + + template <typename T> + 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<DynamicStruct, DynamicStruct>; +}; + +// ------------------------------------------------------------------- + +class DynamicList::Reader { +public: + typedef DynamicList Reads; + + inline Reader(): reader(ElementSize::VOID) {} + + template <typename T, typename = kj::EnableIf<kind<FromReader<T>>() == Kind::LIST>> + inline Reader(T&& value): Reader(toDynamic(value)) {} + + template <typename T> + typename T::Reader as() const; + // Try to convert to any List<T>, 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<const Reader, DynamicValue::Reader> 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 <typename T, Kind k> + friend struct _::PointerHelpers; + friend struct DynamicStruct; + friend class DynamicList::Builder; + template <typename T, ::capnp::Kind k> + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + friend class Orphan<DynamicList>; + friend class Orphan<DynamicValue>; + friend class Orphan<AnyPointer>; +}; + +class DynamicList::Builder { +public: + typedef DynamicList Builds; + + inline Builder(): builder(ElementSize::VOID) {} + inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {} + + template <typename T, typename = kj::EnableIf<kind<FromBuilder<T>>() == Kind::LIST>> + inline Builder(T&& value): Builder(toDynamic(value)) {} + + template <typename T> + typename T::Builder as(); + // Try to convert to any List<T>, 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<DynamicValue>&& orphan); + Orphan<DynamicValue> disown(uint index); + + typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator; + inline Iterator begin() { return Iterator(this, 0); } + inline Iterator end() { return Iterator(this, size()); } + + void copyFrom(std::initializer_list<DynamicValue::Reader> value); + + Reader asReader() const; + +private: + ListSchema schema; + _::ListBuilder builder; + + Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {} + Builder(ListSchema schema, _::OrphanBuilder& orphan); + + template <typename T, Kind k> + friend struct _::PointerHelpers; + friend struct DynamicStruct; + template <typename T, ::capnp::Kind k> + friend struct ::capnp::ToDynamic_; + friend class Orphanage; + template <typename T, Kind k> + friend struct _::OrphanGetImpl; + friend class Orphan<DynamicList>; + friend class Orphan<DynamicValue>; + friend class Orphan<AnyPointer>; +}; + +// ------------------------------------------------------------------- + +class DynamicCapability::Client: public Capability::Client { +public: + typedef DynamicCapability Calls; + typedef DynamicCapability Reads; + + Client() = default; + + template <typename T, typename = kj::EnableIf<kind<FromClient<T>>() == Kind::INTERFACE>> + inline Client(T&& client); + + template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>> + inline Client(kj::Own<T>&& server); + + template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>> + typename T::Client as(); + template <typename T, typename = kj::EnableIf<kind<T>() == 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<DynamicStruct, DynamicStruct> newRequest( + InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr); + Request<DynamicStruct, DynamicStruct> newRequest( + kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr); + +private: + InterfaceSchema schema; + + Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook) + : Capability::Client(kj::mv(hook)), schema(schema) {} + + template <typename T> + inline Client(InterfaceSchema schema, kj::Own<T>&& server); + + friend struct Capability; + friend struct DynamicStruct; + friend struct DynamicList; + friend struct DynamicValue; + friend class Orphan<DynamicCapability>; + friend class Orphan<DynamicValue>; + friend class Orphan<AnyPointer>; + template <typename T, Kind k> + friend struct _::PointerHelpers; +}; + +class DynamicCapability::Server: public Capability::Server { +public: + typedef DynamicCapability Serves; + + Server(InterfaceSchema schema): schema(schema) {} + + virtual kj::Promise<void> call(InterfaceSchema::Method method, + CallContext<DynamicStruct, DynamicStruct> context) = 0; + + kj::Promise<void> dispatchCall(uint64_t interfaceId, uint16_t methodId, + CallContext<AnyPointer, AnyPointer> context) override final; + + inline InterfaceSchema getSchema() const { return schema; } + +private: + InterfaceSchema schema; +}; + +template <> +class Request<DynamicStruct, DynamicStruct>: public DynamicStruct::Builder { + // Specialization of `Request<T, U>` for DynamicStruct. + +public: + inline Request(DynamicStruct::Builder builder, kj::Own<RequestHook>&& hook, + StructSchema resultSchema) + : DynamicStruct::Builder(builder), hook(kj::mv(hook)), resultSchema(resultSchema) {} + + RemotePromise<DynamicStruct> send(); + // Send the call and return a promise for the results. + +private: + kj::Own<RequestHook> hook; + StructSchema resultSchema; + + friend class Capability::Client; + friend struct DynamicCapability; + template <typename, typename> + friend class CallContext; + friend class RequestHook; +}; + +template <> +class CallContext<DynamicStruct, DynamicStruct>: 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<MessageSize> sizeHint = nullptr); + DynamicStruct::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr); + void setResults(DynamicStruct::Reader value); + void adoptResults(Orphan<DynamicStruct>&& value); + Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr); + template <typename SubParams> + kj::Promise<void> tailCall(Request<SubParams, DynamicStruct>&& tailRequest); + void allowCancellation(); + +private: + CallContextHook* hook; + StructSchema paramType; + StructSchema resultType; + + friend class DynamicCapability::Server; +}; + +// ------------------------------------------------------------------- + +// Make sure ReaderFor<T> and BuilderFor<T> work for DynamicEnum, DynamicStruct, and +// DynamicList, so that we can define DynamicValue::as(). + +template <> struct ReaderFor_ <DynamicEnum, Kind::OTHER> { typedef DynamicEnum Type; }; +template <> struct BuilderFor_<DynamicEnum, Kind::OTHER> { typedef DynamicEnum Type; }; +template <> struct ReaderFor_ <DynamicStruct, Kind::OTHER> { typedef DynamicStruct::Reader Type; }; +template <> struct BuilderFor_<DynamicStruct, Kind::OTHER> { typedef DynamicStruct::Builder Type; }; +template <> struct ReaderFor_ <DynamicList, Kind::OTHER> { typedef DynamicList::Reader Type; }; +template <> struct BuilderFor_<DynamicList, Kind::OTHER> { typedef DynamicList::Builder Type; }; +template <> struct ReaderFor_ <DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; }; +template <> struct BuilderFor_<DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; }; +template <> struct PipelineFor_<DynamicCapability, Kind::OTHER> { 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 <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>> + inline Reader(kj::Own<T>&& value); + Reader(ConstSchema constant); + + template <typename T, typename = decltype(toDynamic(kj::instance<T>()))> + 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 <typename T> + inline ReaderFor<T> as() const { return AsImpl<T>::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<T> for any T listed above: Returns List<T>::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 <typename T, Kind kind = kind<T>()> 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 <typename T, typename = decltype(toDynamic(kj::instance<T>()))> + 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 <typename T> + inline BuilderFor<T> as() { return AsImpl<T>::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 <typename T, Kind kind = kind<T>()> 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<DynamicValue>; +}; + +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 <typename T> + inline PipelineFor<T> releaseAs() { return AsImpl<T>::apply(*this); } + + inline Type getType() { return type; } + // Get the type of this value. + +private: + Type type; + union { + DynamicStruct::Pipeline structValue; + DynamicCapability::Client capabilityValue; + }; + + template <typename T, Kind kind = kind<T>()> 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<DynamicStruct> { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template <typename T, typename = kj::EnableIf<kind<T>() == Kind::STRUCT>> + inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {} + + DynamicStruct::Builder get(); + DynamicStruct::Reader getReader() const; + + template <typename T> + Orphan<T> releaseAs(); + // Like DynamicStruct::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is + // transferred to the returned Orphan<T>. + + 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 <typename, Kind> + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan<DynamicValue>; + friend class Orphan<AnyPointer>; + friend class MessageBuilder; +}; + +template <> +class Orphan<DynamicList> { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template <typename T, typename = kj::EnableIf<kind<T>() == Kind::LIST>> + inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {} + + DynamicList::Builder get(); + DynamicList::Reader getReader() const; + + template <typename T> + Orphan<T> releaseAs(); + // Like DynamicList::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is + // transferred to the returned Orphan<T>. + + // 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 <typename, Kind> + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan<DynamicValue>; + friend class Orphan<AnyPointer>; +}; + +template <> +class Orphan<DynamicCapability> { +public: + Orphan() = default; + KJ_DISALLOW_COPY(Orphan); + Orphan(Orphan&&) = default; + Orphan& operator=(Orphan&&) = default; + + template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>> + inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {} + + DynamicCapability::Client get(); + DynamicCapability::Client getReader() const; + + template <typename T> + Orphan<T> releaseAs(); + // Like DynamicCapability::Client::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan<DynamicCapability> is no longer valid after this call; ownership is + // transferred to the returned Orphan<T>. + + 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 <typename, Kind> + friend struct _::PointerHelpers; + friend struct DynamicList; + friend class Orphanage; + friend class Orphan<DynamicValue>; + friend class Orphan<AnyPointer>; +}; + +template <> +class Orphan<DynamicValue> { +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 <typename T> + Orphan(Orphan<T>&&); + Orphan(Orphan<AnyPointer>&&); + 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 <typename T> + Orphan<T> releaseAs(); + // Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, + // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is + // transferred to the returned Orphan<T>. + +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 <typename, Kind> + friend struct _::PointerHelpers; + friend struct DynamicStruct; + friend struct DynamicList; + friend struct AnyPointer; + friend class Orphanage; +}; + +template <typename T> +inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other) + : Orphan(other.get(), kj::mv(other.builder)) {} + +inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other) + : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {} + +template <typename T> +Orphan<T> Orphan<DynamicStruct>::releaseAs() { + get().as<T>(); // type check + return Orphan<T>(kj::mv(builder)); +} + +template <typename T> +Orphan<T> Orphan<DynamicList>::releaseAs() { + get().as<T>(); // type check + return Orphan<T>(kj::mv(builder)); +} + +template <typename T> +Orphan<T> Orphan<DynamicCapability>::releaseAs() { + get().as<T>(); // type check + return Orphan<T>(kj::mv(builder)); +} + +template <typename T> +Orphan<T> Orphan<DynamicValue>::releaseAs() { + get().as<T>(); // type check + type = DynamicValue::UNKNOWN; + return Orphan<T>(kj::mv(builder)); +} + +template <> +Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>(); +template <> +Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>(); +template <> +Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>(); +template <> +Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>(); + +template <> +struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::OTHER> { + static inline _::StructBuilder apply(DynamicStruct::Builder& t) { + return t.builder; + } +}; + +template <> +struct Orphanage::GetInnerBuilder<DynamicList, Kind::OTHER> { + static inline _::ListBuilder apply(DynamicList::Builder& t) { + return t.builder; + } +}; + +template <> +inline Orphan<DynamicStruct> Orphanage::newOrphanCopy<DynamicStruct::Reader>( + DynamicStruct::Reader copyFrom) const { + return Orphan<DynamicStruct>( + copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); +} + +template <> +inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>( + DynamicList::Reader copyFrom) const { + return Orphan<DynamicList>(copyFrom.getSchema(), + _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); +} + +template <> +inline Orphan<DynamicCapability> Orphanage::newOrphanCopy<DynamicCapability::Client>( + DynamicCapability::Client copyFrom) const { + return Orphan<DynamicCapability>( + copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef())); +} + +template <> +Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>( + DynamicValue::Reader copyFrom) const; + +namespace _ { // private + +template <> +struct PointerHelpers<DynamicStruct, Kind::OTHER> { + // 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<DynamicStruct>&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan<DynamicStruct> disown(PointerBuilder builder, StructSchema schema) { + return Orphan<DynamicStruct>(schema, builder.disown()); + } +}; + +template <> +struct PointerHelpers<DynamicList, Kind::OTHER> { + // 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<DynamicList>&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan<DynamicList> disown(PointerBuilder builder, ListSchema schema) { + return Orphan<DynamicList>(schema, builder.disown()); + } +}; + +template <> +struct PointerHelpers<DynamicCapability, Kind::OTHER> { + // 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<DynamicCapability>&& value) { + builder.adopt(kj::mv(value.builder)); + } + static inline Orphan<DynamicCapability> disown(PointerBuilder builder, InterfaceSchema schema) { + return Orphan<DynamicCapability>(schema, builder.disown()); + } +}; + +} // namespace _ (private) + +template <typename T> +inline ReaderFor<T> AnyPointer::Reader::getAs(StructSchema schema) const { + return _::PointerHelpers<T>::getDynamic(reader, schema); +} +template <typename T> +inline ReaderFor<T> AnyPointer::Reader::getAs(ListSchema schema) const { + return _::PointerHelpers<T>::getDynamic(reader, schema); +} +template <typename T> +inline ReaderFor<T> AnyPointer::Reader::getAs(InterfaceSchema schema) const { + return _::PointerHelpers<T>::getDynamic(reader, schema); +} +template <typename T> +inline BuilderFor<T> AnyPointer::Builder::getAs(StructSchema schema) { + return _::PointerHelpers<T>::getDynamic(builder, schema); +} +template <typename T> +inline BuilderFor<T> AnyPointer::Builder::getAs(ListSchema schema) { + return _::PointerHelpers<T>::getDynamic(builder, schema); +} +template <typename T> +inline BuilderFor<T> AnyPointer::Builder::getAs(InterfaceSchema schema) { + return _::PointerHelpers<T>::getDynamic(builder, schema); +} +template <typename T> +inline BuilderFor<T> AnyPointer::Builder::initAs(StructSchema schema) { + return _::PointerHelpers<T>::init(builder, schema); +} +template <typename T> +inline BuilderFor<T> AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) { + return _::PointerHelpers<T>::init(builder, schema, elementCount); +} +template <> +inline void AnyPointer::Builder::setAs<DynamicStruct>(DynamicStruct::Reader value) { + return _::PointerHelpers<DynamicStruct>::set(builder, value); +} +template <> +inline void AnyPointer::Builder::setAs<DynamicList>(DynamicList::Reader value) { + return _::PointerHelpers<DynamicList>::set(builder, value); +} +template <> +inline void AnyPointer::Builder::setAs<DynamicCapability>(DynamicCapability::Client value) { + return _::PointerHelpers<DynamicCapability>::set(builder, kj::mv(value)); +} +template <> +void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan); +template <typename T> +inline Orphan<T> AnyPointer::Builder::disownAs(StructSchema schema) { + return _::PointerHelpers<T>::disown(builder, schema); +} +template <typename T> +inline Orphan<T> AnyPointer::Builder::disownAs(ListSchema schema) { + return _::PointerHelpers<T>::disown(builder, schema); +} +template <typename T> +inline Orphan<T> AnyPointer::Builder::disownAs(InterfaceSchema schema) { + return _::PointerHelpers<T>::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<AnyPointer>::getAs<DynamicStruct>(StructSchema schema) { + return DynamicStruct::Builder(schema, builder); +} +template <> +inline DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>( + StructSchema schema) const { + return DynamicStruct::Reader(schema, builder); +} +template <> +inline Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema) { + return Orphan<DynamicStruct>(schema, kj::mv(builder)); +} +template <> +inline DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema) { + return DynamicList::Builder(schema, builder); +} +template <> +inline DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const { + return DynamicList::Reader(schema, builder); +} +template <> +inline Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema) { + return Orphan<DynamicList>(schema, kj::mv(builder)); +} +template <> +inline DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>( + InterfaceSchema schema) { + return DynamicCapability::Client(schema, builder.asCapability()); +} +template <> +inline DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>( + InterfaceSchema schema) const { + return DynamicCapability::Client(schema, builder.asCapability()); +} +template <> +inline Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>( + InterfaceSchema schema) { + return Orphan<DynamicCapability>(schema, kj::mv(builder)); +} + +// ======================================================================================= +// Inline implementation details. + +template <typename T> +struct ToDynamic_<T, Kind::STRUCT> { + static inline DynamicStruct::Reader apply(const typename T::Reader& value) { + return DynamicStruct::Reader(Schema::from<T>(), value._reader); + } + static inline DynamicStruct::Builder apply(typename T::Builder& value) { + return DynamicStruct::Builder(Schema::from<T>(), value._builder); + } +}; + +template <typename T> +struct ToDynamic_<T, Kind::LIST> { + static inline DynamicList::Reader apply(const typename T::Reader& value) { + return DynamicList::Reader(Schema::from<T>(), value.reader); + } + static inline DynamicList::Builder apply(typename T::Builder& value) { + return DynamicList::Builder(Schema::from<T>(), value.builder); + } +}; + +template <typename T> +struct ToDynamic_<T, Kind::INTERFACE> { + 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 <typename T> +ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) { + return ToDynamic_<FromReader<T>>::apply(value); +} +template <typename T> +BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) { + return ToDynamic_<FromBuilder<T>>::apply(value); +} +template <typename T> +DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) { + return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value)); +} +template <typename T> +typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) { + return typename FromServer<T>::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<DynamicValue>::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 <typename T, typename> +inline DynamicValue::Reader::Reader(kj::Own<T>&& 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<typeName> { \ + static ReaderFor<typeName> apply(const Reader& reader); \ +}; \ +template <> \ +struct DynamicValue::Builder::AsImpl<typeName> { \ + static BuilderFor<typeName> 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<Void> { + static Void apply(const Reader& reader); +}; +template <> +struct DynamicValue::Builder::AsImpl<Void> { + static Void apply(Builder& builder); +}; + +template <typename T> +struct DynamicValue::Reader::AsImpl<T, Kind::ENUM> { + static T apply(const Reader& reader) { + return reader.as<DynamicEnum>().as<T>(); + } +}; +template <typename T> +struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> { + static T apply(Builder& builder) { + return builder.as<DynamicEnum>().as<T>(); + } +}; + +template <typename T> +struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> { + static typename T::Reader apply(const Reader& reader) { + return reader.as<DynamicStruct>().as<T>(); + } +}; +template <typename T> +struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> { + static typename T::Builder apply(Builder& builder) { + return builder.as<DynamicStruct>().as<T>(); + } +}; + +template <typename T> +struct DynamicValue::Reader::AsImpl<T, Kind::LIST> { + static typename T::Reader apply(const Reader& reader) { + return reader.as<DynamicList>().as<T>(); + } +}; +template <typename T> +struct DynamicValue::Builder::AsImpl<T, Kind::LIST> { + static typename T::Builder apply(Builder& builder) { + return builder.as<DynamicList>().as<T>(); + } +}; + +template <typename T> +struct DynamicValue::Reader::AsImpl<T, Kind::INTERFACE> { + static typename T::Client apply(const Reader& reader) { + return reader.as<DynamicCapability>().as<T>(); + } +}; +template <typename T> +struct DynamicValue::Builder::AsImpl<T, Kind::INTERFACE> { + static typename T::Client apply(Builder& builder) { + return builder.as<DynamicCapability>().as<T>(); + } +}; + +template <> +struct DynamicValue::Reader::AsImpl<DynamicValue> { + static DynamicValue::Reader apply(const Reader& reader) { + return reader; + } +}; +template <> +struct DynamicValue::Builder::AsImpl<DynamicValue> { + 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 <typename T> +struct DynamicValue::Pipeline::AsImpl<T, Kind::STRUCT> { + static typename T::Pipeline apply(Pipeline& pipeline) { + return pipeline.releaseAs<DynamicStruct>().releaseAs<T>(); + } +}; +template <typename T> +struct DynamicValue::Pipeline::AsImpl<T, Kind::INTERFACE> { + static typename T::Client apply(Pipeline& pipeline) { + return pipeline.releaseAs<DynamicCapability>().releaseAs<T>(); + } +}; +template <> +struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> { + static PipelineFor<DynamicStruct> apply(Pipeline& pipeline); +}; +template <> +struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> { + static PipelineFor<DynamicCapability> apply(Pipeline& pipeline); +}; + +// ------------------------------------------------------------------- + +template <typename T> +typename T::Reader DynamicStruct::Reader::as() const { + static_assert(kind<T>() == Kind::STRUCT, + "DynamicStruct::Reader::as<T>() can only convert to struct types."); + schema.requireUsableAs<T>(); + return typename T::Reader(reader); +} + +template <typename T> +typename T::Builder DynamicStruct::Builder::as() { + static_assert(kind<T>() == Kind::STRUCT, + "DynamicStruct::Builder::as<T>() can only convert to struct types."); + schema.requireUsableAs<T>(); + return typename T::Builder(builder); +} + +template <> +inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const { + return *this; +} +template <> +inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() { + return *this; +} + +inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const { + return DynamicStruct::Reader(schema, builder.asReader()); +} + +template <> +inline AnyStruct::Reader DynamicStruct::Reader::as<AnyStruct>() const { + return AnyStruct::Reader(reader); +} + +template <> +inline AnyStruct::Builder DynamicStruct::Builder::as<AnyStruct>() { + return AnyStruct::Builder(builder); +} + +template <typename T> +typename T::Pipeline DynamicStruct::Pipeline::releaseAs() { + static_assert(kind<T>() == Kind::STRUCT, + "DynamicStruct::Pipeline::releaseAs<T>() can only convert to struct types."); + schema.requireUsableAs<T>(); + return typename T::Pipeline(kj::mv(typeless)); +} + +// ------------------------------------------------------------------- + +template <typename T> +typename T::Reader DynamicList::Reader::as() const { + static_assert(kind<T>() == Kind::LIST, + "DynamicStruct::Reader::as<T>() can only convert to list types."); + schema.requireUsableAs<T>(); + return typename T::Reader(reader); +} +template <typename T> +typename T::Builder DynamicList::Builder::as() { + static_assert(kind<T>() == Kind::LIST, + "DynamicStruct::Builder::as<T>() can only convert to list types."); + schema.requireUsableAs<T>(); + return typename T::Builder(builder); +} + +template <> +inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const { + return *this; +} +template <> +inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() { + return *this; +} + +template <> +inline AnyList::Reader DynamicList::Reader::as<AnyList>() const { + return AnyList::Reader(reader); +} + +template <> +inline AnyList::Builder DynamicList::Builder::as<AnyList>() { + return AnyList::Builder(builder); +} + +// ------------------------------------------------------------------- + +template <typename T, typename> +inline DynamicCapability::Client::Client(T&& client) + : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {} + +template <typename T, typename> +inline DynamicCapability::Client::Client(kj::Own<T>&& server) + : Client(server->getSchema(), kj::mv(server)) {} +template <typename T> +inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server) + : Capability::Client(kj::mv(server)), schema(schema) {} + +template <typename T, typename> +typename T::Client DynamicCapability::Client::as() { + static_assert(kind<T>() == Kind::INTERFACE, + "DynamicCapability::Client::as<T>() can only convert to interface types."); + schema.requireUsableAs<T>(); + return typename T::Client(hook->addRef()); +} + +template <typename T, typename> +typename T::Client DynamicCapability::Client::releaseAs() { + static_assert(kind<T>() == Kind::INTERFACE, + "DynamicCapability::Client::as<T>() can only convert to interface types."); + schema.requireUsableAs<T>(); + return typename T::Client(kj::mv(hook)); +} + +inline CallContext<DynamicStruct, DynamicStruct>::CallContext( + CallContextHook& hook, StructSchema paramType, StructSchema resultType) + : hook(&hook), paramType(paramType), resultType(resultType) {} +inline DynamicStruct::Reader CallContext<DynamicStruct, DynamicStruct>::getParams() { + return hook->getParams().getAs<DynamicStruct>(paramType); +} +inline void CallContext<DynamicStruct, DynamicStruct>::releaseParams() { + hook->releaseParams(); +} +inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::getResults( + kj::Maybe<MessageSize> sizeHint) { + return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType); +} +inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults( + kj::Maybe<MessageSize> sizeHint) { + return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType); +} +inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) { + hook->getResults(value.totalSize()).setAs<DynamicStruct>(value); +} +inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) { + hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value)); +} +inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage( + kj::Maybe<MessageSize> sizeHint) { + return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); +} +template <typename SubParams> +inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall( + Request<SubParams, DynamicStruct>&& tailRequest) { + return hook->tailCall(kj::mv(tailRequest.hook)); +} +inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() { + hook->allowCancellation(); +} + +template <> +inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>( + InterfaceSchema schema) { + return DynamicCapability::Client(schema, hook->addRef()); +} + +// ------------------------------------------------------------------- + +template <typename T> +ReaderFor<T> ConstSchema::as() const { + return DynamicValue::Reader(*this).as<T>(); +} + +} // namespace capnp + +#endif // CAPNP_DYNAMIC_H_