You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					1644 lines
				
				59 KiB
			
		
		
			
		
	
	
					1644 lines
				
				59 KiB
			| 
											8 years ago
										 | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
 | ||
|  | // Licensed under the MIT License:
 | ||
|  | //
 | ||
|  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | ||
|  | // of this software and associated documentation files (the "Software"), to deal
 | ||
|  | // in the Software without restriction, including without limitation the rights
 | ||
|  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | ||
|  | // copies of the Software, and to permit persons to whom the Software is
 | ||
|  | // furnished to do so, subject to the following conditions:
 | ||
|  | //
 | ||
|  | // The above copyright notice and this permission notice shall be included in
 | ||
|  | // all copies or substantial portions of the Software.
 | ||
|  | //
 | ||
|  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | ||
|  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | ||
|  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | ||
|  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | ||
|  | // LIABILITY, WHETHER IN AN ACTION 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_
 |