cannam@149: // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors cannam@149: // Licensed under the MIT License: cannam@149: // cannam@149: // Permission is hereby granted, free of charge, to any person obtaining a copy cannam@149: // of this software and associated documentation files (the "Software"), to deal cannam@149: // in the Software without restriction, including without limitation the rights cannam@149: // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell cannam@149: // copies of the Software, and to permit persons to whom the Software is cannam@149: // furnished to do so, subject to the following conditions: cannam@149: // cannam@149: // The above copyright notice and this permission notice shall be included in cannam@149: // all copies or substantial portions of the Software. cannam@149: // cannam@149: // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cannam@149: // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cannam@149: // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cannam@149: // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cannam@149: // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, cannam@149: // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN cannam@149: // THE SOFTWARE. cannam@149: cannam@149: // This file defines classes that can be used to manipulate messages based on schemas that are not cannam@149: // known until runtime. This is also useful for writing generic code that uses schemas to handle cannam@149: // arbitrary types in a generic way. cannam@149: // cannam@149: // Each of the classes defined here has a to() template method which converts an instance back to a cannam@149: // native type. This method will throw an exception if the requested type does not match the cannam@149: // schema. To convert native types to dynamic, use DynamicFactory. cannam@149: // cannam@149: // As always, underlying data is validated lazily, so you have to actually traverse the whole cannam@149: // message if you want to validate all content. cannam@149: cannam@149: #ifndef CAPNP_DYNAMIC_H_ cannam@149: #define CAPNP_DYNAMIC_H_ cannam@149: cannam@149: #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) cannam@149: #pragma GCC system_header cannam@149: #endif cannam@149: cannam@149: #include "schema.h" cannam@149: #include "layout.h" cannam@149: #include "message.h" cannam@149: #include "any.h" cannam@149: #include "capability.h" cannam@149: cannam@149: namespace capnp { cannam@149: cannam@149: class MessageReader; cannam@149: class MessageBuilder; cannam@149: cannam@149: struct DynamicValue { cannam@149: DynamicValue() = delete; cannam@149: cannam@149: enum Type { cannam@149: UNKNOWN, cannam@149: // Means that the value has unknown type and content because it comes from a newer version of cannam@149: // the schema, or from a newer version of Cap'n Proto that has new features that this version cannam@149: // doesn't understand. cannam@149: cannam@149: VOID, cannam@149: BOOL, cannam@149: INT, cannam@149: UINT, cannam@149: FLOAT, cannam@149: TEXT, cannam@149: DATA, cannam@149: LIST, cannam@149: ENUM, cannam@149: STRUCT, cannam@149: CAPABILITY, cannam@149: ANY_POINTER cannam@149: }; cannam@149: cannam@149: class Reader; cannam@149: class Builder; cannam@149: class Pipeline; cannam@149: }; cannam@149: class DynamicEnum; cannam@149: struct DynamicStruct { cannam@149: DynamicStruct() = delete; cannam@149: class Reader; cannam@149: class Builder; cannam@149: class Pipeline; cannam@149: }; cannam@149: struct DynamicList { cannam@149: DynamicList() = delete; cannam@149: class Reader; cannam@149: class Builder; cannam@149: }; cannam@149: struct DynamicCapability { cannam@149: DynamicCapability() = delete; cannam@149: class Client; cannam@149: class Server; cannam@149: }; cannam@149: template <> class Orphan; cannam@149: cannam@149: template struct DynamicTypeFor_; cannam@149: template <> struct DynamicTypeFor_ { typedef DynamicEnum Type; }; cannam@149: template <> struct DynamicTypeFor_ { typedef DynamicStruct Type; }; cannam@149: template <> struct DynamicTypeFor_ { typedef DynamicList Type; }; cannam@149: template <> struct DynamicTypeFor_ { typedef DynamicCapability Type; }; cannam@149: cannam@149: template cannam@149: using DynamicTypeFor = typename DynamicTypeFor_()>::Type; cannam@149: cannam@149: template cannam@149: ReaderFor>> toDynamic(T&& value); cannam@149: template cannam@149: BuilderFor>> toDynamic(T&& value); cannam@149: template cannam@149: DynamicTypeFor> toDynamic(T&& value); cannam@149: template cannam@149: typename DynamicTypeFor>::Client toDynamic(kj::Own&& value); cannam@149: cannam@149: namespace _ { // private cannam@149: cannam@149: template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; cannam@149: template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; cannam@149: template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; cannam@149: template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; cannam@149: template <> struct Kind_ { static constexpr Kind kind = Kind::OTHER; }; cannam@149: cannam@149: } // namespace _ (private) cannam@149: cannam@149: template <> inline constexpr Style style() { return Style::POINTER; } cannam@149: template <> inline constexpr Style style() { return Style::PRIMITIVE; } cannam@149: template <> inline constexpr Style style() { return Style::STRUCT; } cannam@149: template <> inline constexpr Style style() { return Style::POINTER; } cannam@149: template <> inline constexpr Style style() { return Style::CAPABILITY; } cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class DynamicEnum { cannam@149: public: cannam@149: DynamicEnum() = default; cannam@149: inline DynamicEnum(EnumSchema::Enumerant enumerant) cannam@149: : schema(enumerant.getContainingEnum()), value(enumerant.getOrdinal()) {} cannam@149: inline DynamicEnum(EnumSchema schema, uint16_t value) cannam@149: : schema(schema), value(value) {} cannam@149: cannam@149: template () == Kind::ENUM>> cannam@149: inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {} cannam@149: cannam@149: template cannam@149: inline T as() const { return static_cast(asImpl(typeId())); } cannam@149: // Cast to a native enum type. cannam@149: cannam@149: inline EnumSchema getSchema() const { return schema; } cannam@149: cannam@149: kj::Maybe getEnumerant() const; cannam@149: // Get which enumerant this enum value represents. Returns nullptr if the numeric value does not cannam@149: // correspond to any enumerant in the schema -- this can happen if the data was built using a cannam@149: // newer schema that has more values defined. cannam@149: cannam@149: inline uint16_t getRaw() const { return value; } cannam@149: // Returns the raw underlying enum value. cannam@149: cannam@149: private: cannam@149: EnumSchema schema; cannam@149: uint16_t value; cannam@149: cannam@149: uint16_t asImpl(uint64_t requestedTypeId) const; cannam@149: cannam@149: friend struct DynamicStruct; cannam@149: friend struct DynamicList; cannam@149: friend struct DynamicValue; cannam@149: template cannam@149: friend DynamicTypeFor> toDynamic(T&& value); cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class DynamicStruct::Reader { cannam@149: public: cannam@149: typedef DynamicStruct Reads; cannam@149: cannam@149: Reader() = default; cannam@149: cannam@149: template >() == Kind::STRUCT>> cannam@149: inline Reader(T&& value): Reader(toDynamic(value)) {} cannam@149: cannam@149: inline MessageSize totalSize() const { return reader.totalSize().asPublic(); } cannam@149: cannam@149: template cannam@149: typename T::Reader as() const; cannam@149: // Convert the dynamic struct to its compiled-in type. cannam@149: cannam@149: inline StructSchema getSchema() const { return schema; } cannam@149: cannam@149: DynamicValue::Reader get(StructSchema::Field field) const; cannam@149: // Read the given field value. cannam@149: cannam@149: bool has(StructSchema::Field field) const; cannam@149: // Tests whether the given field is set to its default value. For pointer values, this does cannam@149: // not actually traverse the value comparing it with the default, but simply returns true if the cannam@149: // pointer is non-null. For members of unions, has() returns false if the union member is not cannam@149: // active, but does not necessarily return true if the member is active (depends on the field's cannam@149: // value). cannam@149: cannam@149: kj::Maybe which() const; cannam@149: // If the struct contains an (unnamed) union, and the currently-active field within that union cannam@149: // is known, this returns that field. Otherwise, it returns null. In other words, this returns cannam@149: // null if there is no union present _or_ if the union's discriminant is set to an unrecognized cannam@149: // value. This could happen in particular when receiving a message from a sender who has a cannam@149: // newer version of the protocol and is using a field of the union that you don't know about yet. cannam@149: cannam@149: DynamicValue::Reader get(kj::StringPtr name) const; cannam@149: bool has(kj::StringPtr name) const; cannam@149: // Shortcuts to access fields by name. These throw exceptions if no such field exists. cannam@149: cannam@149: private: cannam@149: StructSchema schema; cannam@149: _::StructReader reader; cannam@149: cannam@149: inline Reader(StructSchema schema, _::StructReader reader) cannam@149: : schema(schema), reader(reader) {} cannam@149: Reader(StructSchema schema, const _::OrphanBuilder& orphan); cannam@149: cannam@149: bool isSetInUnion(StructSchema::Field field) const; cannam@149: void verifySetInUnion(StructSchema::Field field) const; cannam@149: static DynamicValue::Reader getImpl(_::StructReader reader, StructSchema::Field field); cannam@149: cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: friend class DynamicStruct::Builder; cannam@149: friend struct DynamicList; cannam@149: friend class MessageReader; cannam@149: friend class MessageBuilder; cannam@149: template cannam@149: friend struct ::capnp::ToDynamic_; cannam@149: friend kj::StringTree _::structString( cannam@149: _::StructReader reader, const _::RawBrandedSchema& schema); cannam@149: friend class Orphanage; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: }; cannam@149: cannam@149: class DynamicStruct::Builder { cannam@149: public: cannam@149: typedef DynamicStruct Builds; cannam@149: cannam@149: Builder() = default; cannam@149: inline Builder(decltype(nullptr)) {} cannam@149: cannam@149: template >() == Kind::STRUCT>> cannam@149: inline Builder(T&& value): Builder(toDynamic(value)) {} cannam@149: cannam@149: inline MessageSize totalSize() const { return asReader().totalSize(); } cannam@149: cannam@149: template cannam@149: typename T::Builder as(); cannam@149: // Cast to a particular struct type. cannam@149: cannam@149: inline StructSchema getSchema() const { return schema; } cannam@149: cannam@149: DynamicValue::Builder get(StructSchema::Field field); cannam@149: // Read the given field value. cannam@149: cannam@149: inline bool has(StructSchema::Field field) { return asReader().has(field); } cannam@149: // Tests whether the given field is set to its default value. For pointer values, this does cannam@149: // not actually traverse the value comparing it with the default, but simply returns true if the cannam@149: // pointer is non-null. For members of unions, has() returns whether the field is currently cannam@149: // active and the union as a whole is non-default -- so, the only time has() will return false cannam@149: // for an active union field is if it is the default active field and it has its default value. cannam@149: cannam@149: kj::Maybe which(); cannam@149: // If the struct contains an (unnamed) union, and the currently-active field within that union cannam@149: // is known, this returns that field. Otherwise, it returns null. In other words, this returns cannam@149: // null if there is no union present _or_ if the union's discriminant is set to an unrecognized cannam@149: // value. This could happen in particular when receiving a message from a sender who has a cannam@149: // newer version of the protocol and is using a field of the union that you don't know about yet. cannam@149: cannam@149: void set(StructSchema::Field field, const DynamicValue::Reader& value); cannam@149: // Set the given field value. cannam@149: cannam@149: DynamicValue::Builder init(StructSchema::Field field); cannam@149: DynamicValue::Builder init(StructSchema::Field field, uint size); cannam@149: // Init a struct, list, or blob field. cannam@149: cannam@149: void adopt(StructSchema::Field field, Orphan&& orphan); cannam@149: Orphan disown(StructSchema::Field field); cannam@149: // Adopt/disown. This works even for non-pointer fields: adopt() becomes equivalent to set() cannam@149: // and disown() becomes like get() followed by clear(). cannam@149: cannam@149: void clear(StructSchema::Field field); cannam@149: // Clear a field, setting it to its default value. For pointer fields, this actually makes the cannam@149: // field null. cannam@149: cannam@149: DynamicValue::Builder get(kj::StringPtr name); cannam@149: bool has(kj::StringPtr name); cannam@149: void set(kj::StringPtr name, const DynamicValue::Reader& value); cannam@149: void set(kj::StringPtr name, std::initializer_list value); cannam@149: DynamicValue::Builder init(kj::StringPtr name); cannam@149: DynamicValue::Builder init(kj::StringPtr name, uint size); cannam@149: void adopt(kj::StringPtr name, Orphan&& orphan); cannam@149: Orphan disown(kj::StringPtr name); cannam@149: void clear(kj::StringPtr name); cannam@149: // Shortcuts to access fields by name. These throw exceptions if no such field exists. cannam@149: cannam@149: Reader asReader() const; cannam@149: cannam@149: private: cannam@149: StructSchema schema; cannam@149: _::StructBuilder builder; cannam@149: cannam@149: inline Builder(StructSchema schema, _::StructBuilder builder) cannam@149: : schema(schema), builder(builder) {} cannam@149: Builder(StructSchema schema, _::OrphanBuilder& orphan); cannam@149: cannam@149: bool isSetInUnion(StructSchema::Field field); cannam@149: void verifySetInUnion(StructSchema::Field field); cannam@149: void setInUnion(StructSchema::Field field); cannam@149: cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: friend struct DynamicList; cannam@149: friend class MessageReader; cannam@149: friend class MessageBuilder; cannam@149: template cannam@149: friend struct ::capnp::ToDynamic_; cannam@149: friend class Orphanage; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: }; cannam@149: cannam@149: class DynamicStruct::Pipeline { cannam@149: public: cannam@149: typedef DynamicStruct Pipelines; cannam@149: cannam@149: inline Pipeline(decltype(nullptr)): typeless(nullptr) {} cannam@149: cannam@149: template cannam@149: typename T::Pipeline releaseAs(); cannam@149: // Convert the dynamic pipeline to its compiled-in type. cannam@149: cannam@149: inline StructSchema getSchema() { return schema; } cannam@149: cannam@149: DynamicValue::Pipeline get(StructSchema::Field field); cannam@149: // Read the given field value. cannam@149: cannam@149: DynamicValue::Pipeline get(kj::StringPtr name); cannam@149: // Get by string name. cannam@149: cannam@149: private: cannam@149: StructSchema schema; cannam@149: AnyPointer::Pipeline typeless; cannam@149: cannam@149: inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless) cannam@149: : schema(schema), typeless(kj::mv(typeless)) {} cannam@149: cannam@149: friend class Request; cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class DynamicList::Reader { cannam@149: public: cannam@149: typedef DynamicList Reads; cannam@149: cannam@149: inline Reader(): reader(ElementSize::VOID) {} cannam@149: cannam@149: template >() == Kind::LIST>> cannam@149: inline Reader(T&& value): Reader(toDynamic(value)) {} cannam@149: cannam@149: template cannam@149: typename T::Reader as() const; cannam@149: // Try to convert to any List, Data, or Text. Throws an exception if the underlying data cannam@149: // can't possibly represent the requested type. cannam@149: cannam@149: inline ListSchema getSchema() const { return schema; } cannam@149: cannam@149: inline uint size() const { return unbound(reader.size() / ELEMENTS); } cannam@149: DynamicValue::Reader operator[](uint index) const; cannam@149: cannam@149: typedef _::IndexingIterator Iterator; cannam@149: inline Iterator begin() const { return Iterator(this, 0); } cannam@149: inline Iterator end() const { return Iterator(this, size()); } cannam@149: cannam@149: private: cannam@149: ListSchema schema; cannam@149: _::ListReader reader; cannam@149: cannam@149: Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {} cannam@149: Reader(ListSchema schema, const _::OrphanBuilder& orphan); cannam@149: cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: friend struct DynamicStruct; cannam@149: friend class DynamicList::Builder; cannam@149: template cannam@149: friend struct ::capnp::ToDynamic_; cannam@149: friend class Orphanage; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: }; cannam@149: cannam@149: class DynamicList::Builder { cannam@149: public: cannam@149: typedef DynamicList Builds; cannam@149: cannam@149: inline Builder(): builder(ElementSize::VOID) {} cannam@149: inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {} cannam@149: cannam@149: template >() == Kind::LIST>> cannam@149: inline Builder(T&& value): Builder(toDynamic(value)) {} cannam@149: cannam@149: template cannam@149: typename T::Builder as(); cannam@149: // Try to convert to any List, Data, or Text. Throws an exception if the underlying data cannam@149: // can't possibly represent the requested type. cannam@149: cannam@149: inline ListSchema getSchema() const { return schema; } cannam@149: cannam@149: inline uint size() const { return unbound(builder.size() / ELEMENTS); } cannam@149: DynamicValue::Builder operator[](uint index); cannam@149: void set(uint index, const DynamicValue::Reader& value); cannam@149: DynamicValue::Builder init(uint index, uint size); cannam@149: void adopt(uint index, Orphan&& orphan); cannam@149: Orphan disown(uint index); cannam@149: cannam@149: typedef _::IndexingIterator Iterator; cannam@149: inline Iterator begin() { return Iterator(this, 0); } cannam@149: inline Iterator end() { return Iterator(this, size()); } cannam@149: cannam@149: void copyFrom(std::initializer_list value); cannam@149: cannam@149: Reader asReader() const; cannam@149: cannam@149: private: cannam@149: ListSchema schema; cannam@149: _::ListBuilder builder; cannam@149: cannam@149: Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {} cannam@149: Builder(ListSchema schema, _::OrphanBuilder& orphan); cannam@149: cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: friend struct DynamicStruct; cannam@149: template cannam@149: friend struct ::capnp::ToDynamic_; cannam@149: friend class Orphanage; cannam@149: template cannam@149: friend struct _::OrphanGetImpl; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: class DynamicCapability::Client: public Capability::Client { cannam@149: public: cannam@149: typedef DynamicCapability Calls; cannam@149: typedef DynamicCapability Reads; cannam@149: cannam@149: Client() = default; cannam@149: cannam@149: template >() == Kind::INTERFACE>> cannam@149: inline Client(T&& client); cannam@149: cannam@149: template ()>> cannam@149: inline Client(kj::Own&& server); cannam@149: cannam@149: template () == Kind::INTERFACE>> cannam@149: typename T::Client as(); cannam@149: template () == Kind::INTERFACE>> cannam@149: typename T::Client releaseAs(); cannam@149: // Convert to any client type. cannam@149: cannam@149: Client upcast(InterfaceSchema requestedSchema); cannam@149: // Upcast to a superclass. Throws an exception if `schema` is not a superclass. cannam@149: cannam@149: inline InterfaceSchema getSchema() { return schema; } cannam@149: cannam@149: Request newRequest( cannam@149: InterfaceSchema::Method method, kj::Maybe sizeHint = nullptr); cannam@149: Request newRequest( cannam@149: kj::StringPtr methodName, kj::Maybe sizeHint = nullptr); cannam@149: cannam@149: private: cannam@149: InterfaceSchema schema; cannam@149: cannam@149: Client(InterfaceSchema schema, kj::Own&& hook) cannam@149: : Capability::Client(kj::mv(hook)), schema(schema) {} cannam@149: cannam@149: template cannam@149: inline Client(InterfaceSchema schema, kj::Own&& server); cannam@149: cannam@149: friend struct Capability; cannam@149: friend struct DynamicStruct; cannam@149: friend struct DynamicList; cannam@149: friend struct DynamicValue; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: }; cannam@149: cannam@149: class DynamicCapability::Server: public Capability::Server { cannam@149: public: cannam@149: typedef DynamicCapability Serves; cannam@149: cannam@149: Server(InterfaceSchema schema): schema(schema) {} cannam@149: cannam@149: virtual kj::Promise call(InterfaceSchema::Method method, cannam@149: CallContext context) = 0; cannam@149: cannam@149: kj::Promise dispatchCall(uint64_t interfaceId, uint16_t methodId, cannam@149: CallContext context) override final; cannam@149: cannam@149: inline InterfaceSchema getSchema() const { return schema; } cannam@149: cannam@149: private: cannam@149: InterfaceSchema schema; cannam@149: }; cannam@149: cannam@149: template <> cannam@149: class Request: public DynamicStruct::Builder { cannam@149: // Specialization of `Request` for DynamicStruct. cannam@149: cannam@149: public: cannam@149: inline Request(DynamicStruct::Builder builder, kj::Own&& hook, cannam@149: StructSchema resultSchema) cannam@149: : DynamicStruct::Builder(builder), hook(kj::mv(hook)), resultSchema(resultSchema) {} cannam@149: cannam@149: RemotePromise send(); cannam@149: // Send the call and return a promise for the results. cannam@149: cannam@149: private: cannam@149: kj::Own hook; cannam@149: StructSchema resultSchema; cannam@149: cannam@149: friend class Capability::Client; cannam@149: friend struct DynamicCapability; cannam@149: template cannam@149: friend class CallContext; cannam@149: friend class RequestHook; cannam@149: }; cannam@149: cannam@149: template <> cannam@149: class CallContext: public kj::DisallowConstCopy { cannam@149: // Wrapper around CallContextHook with a specific return type. cannam@149: // cannam@149: // Methods of this class may only be called from within the server's event loop, not from other cannam@149: // threads. cannam@149: cannam@149: public: cannam@149: explicit CallContext(CallContextHook& hook, StructSchema paramType, StructSchema resultType); cannam@149: cannam@149: DynamicStruct::Reader getParams(); cannam@149: void releaseParams(); cannam@149: DynamicStruct::Builder getResults(kj::Maybe sizeHint = nullptr); cannam@149: DynamicStruct::Builder initResults(kj::Maybe sizeHint = nullptr); cannam@149: void setResults(DynamicStruct::Reader value); cannam@149: void adoptResults(Orphan&& value); cannam@149: Orphanage getResultsOrphanage(kj::Maybe sizeHint = nullptr); cannam@149: template cannam@149: kj::Promise tailCall(Request&& tailRequest); cannam@149: void allowCancellation(); cannam@149: cannam@149: private: cannam@149: CallContextHook* hook; cannam@149: StructSchema paramType; cannam@149: StructSchema resultType; cannam@149: cannam@149: friend class DynamicCapability::Server; cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: // Make sure ReaderFor and BuilderFor work for DynamicEnum, DynamicStruct, and cannam@149: // DynamicList, so that we can define DynamicValue::as(). cannam@149: cannam@149: template <> struct ReaderFor_ { typedef DynamicEnum Type; }; cannam@149: template <> struct BuilderFor_ { typedef DynamicEnum Type; }; cannam@149: template <> struct ReaderFor_ { typedef DynamicStruct::Reader Type; }; cannam@149: template <> struct BuilderFor_ { typedef DynamicStruct::Builder Type; }; cannam@149: template <> struct ReaderFor_ { typedef DynamicList::Reader Type; }; cannam@149: template <> struct BuilderFor_ { typedef DynamicList::Builder Type; }; cannam@149: template <> struct ReaderFor_ { typedef DynamicCapability::Client Type; }; cannam@149: template <> struct BuilderFor_ { typedef DynamicCapability::Client Type; }; cannam@149: template <> struct PipelineFor_ { typedef DynamicCapability::Client Type; }; cannam@149: cannam@149: class DynamicValue::Reader { cannam@149: public: cannam@149: typedef DynamicValue Reads; cannam@149: cannam@149: inline Reader(decltype(nullptr) n = nullptr); // UNKNOWN cannam@149: inline Reader(Void value); cannam@149: inline Reader(bool value); cannam@149: inline Reader(char value); cannam@149: inline Reader(signed char value); cannam@149: inline Reader(short value); cannam@149: inline Reader(int value); cannam@149: inline Reader(long value); cannam@149: inline Reader(long long value); cannam@149: inline Reader(unsigned char value); cannam@149: inline Reader(unsigned short value); cannam@149: inline Reader(unsigned int value); cannam@149: inline Reader(unsigned long value); cannam@149: inline Reader(unsigned long long value); cannam@149: inline Reader(float value); cannam@149: inline Reader(double value); cannam@149: inline Reader(const char* value); // Text cannam@149: inline Reader(const Text::Reader& value); cannam@149: inline Reader(const Data::Reader& value); cannam@149: inline Reader(const DynamicList::Reader& value); cannam@149: inline Reader(DynamicEnum value); cannam@149: inline Reader(const DynamicStruct::Reader& value); cannam@149: inline Reader(const AnyPointer::Reader& value); cannam@149: inline Reader(DynamicCapability::Client& value); cannam@149: inline Reader(DynamicCapability::Client&& value); cannam@149: template ()>> cannam@149: inline Reader(kj::Own&& value); cannam@149: Reader(ConstSchema constant); cannam@149: cannam@149: template ()))> cannam@149: inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {} cannam@149: cannam@149: Reader(const Reader& other); cannam@149: Reader(Reader&& other) noexcept; cannam@149: ~Reader() noexcept(false); cannam@149: Reader& operator=(const Reader& other); cannam@149: Reader& operator=(Reader&& other); cannam@149: // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not cannam@149: // trivially copyable. cannam@149: cannam@149: template cannam@149: inline ReaderFor as() const { return AsImpl::apply(*this); } cannam@149: // Use to interpret the value as some Cap'n Proto type. Allowed types are: cannam@149: // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum: Returns the raw value. cannam@149: // - Text, Data, AnyPointer, any struct type: Returns the corresponding Reader. cannam@149: // - List for any T listed above: Returns List::Reader. cannam@149: // - DynamicEnum: Returns the corresponding type. cannam@149: // - DynamicStruct, DynamicList: Returns the corresponding Reader. cannam@149: // - Any capability type, including DynamicCapability: Returns the corresponding Client. cannam@149: // - DynamicValue: Returns an identical Reader. Useful to avoid special-casing in generic code. cannam@149: // (TODO(perf): On GCC 4.8 / Clang 3.3, provide rvalue-qualified version that avoids cannam@149: // refcounting.) cannam@149: // cannam@149: // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier. cannam@149: // - Any integer can be converted to any other integer type so long as the actual value is within cannam@149: // the new type's range. cannam@149: // - Floating-point types can be converted to integers as long as no information would be lost cannam@149: // in the conversion. cannam@149: // - Integers can be converted to floating points. This may lose information, but won't throw. cannam@149: // - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose cannam@149: // information, but won't throw. cannam@149: // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not cannam@149: // vice-versa). cannam@149: // - Capabilities can be upcast (cast to a supertype), but not downcast. cannam@149: // cannam@149: // Any other conversion attempt will throw an exception. cannam@149: cannam@149: inline Type getType() const { return type; } cannam@149: // Get the type of this value. cannam@149: cannam@149: private: cannam@149: Type type; cannam@149: cannam@149: union { cannam@149: Void voidValue; cannam@149: bool boolValue; cannam@149: int64_t intValue; cannam@149: uint64_t uintValue; cannam@149: double floatValue; cannam@149: Text::Reader textValue; cannam@149: Data::Reader dataValue; cannam@149: DynamicList::Reader listValue; cannam@149: DynamicEnum enumValue; cannam@149: DynamicStruct::Reader structValue; cannam@149: AnyPointer::Reader anyPointerValue; cannam@149: cannam@149: mutable DynamicCapability::Client capabilityValue; cannam@149: // Declared mutable because `Client`s normally cannot be const. cannam@149: cannam@149: // Warning: Copy/move constructors assume all these types are trivially copyable except cannam@149: // Capability. cannam@149: }; cannam@149: cannam@149: template ()> struct AsImpl; cannam@149: // Implementation backing the as() method. Needs to be a struct to allow partial cannam@149: // specialization. Has a method apply() which does the work. cannam@149: cannam@149: friend class Orphanage; // to speed up newOrphanCopy(DynamicValue::Reader) cannam@149: }; cannam@149: cannam@149: class DynamicValue::Builder { cannam@149: public: cannam@149: typedef DynamicValue Builds; cannam@149: cannam@149: inline Builder(decltype(nullptr) n = nullptr); // UNKNOWN cannam@149: inline Builder(Void value); cannam@149: inline Builder(bool value); cannam@149: inline Builder(char value); cannam@149: inline Builder(signed char value); cannam@149: inline Builder(short value); cannam@149: inline Builder(int value); cannam@149: inline Builder(long value); cannam@149: inline Builder(long long value); cannam@149: inline Builder(unsigned char value); cannam@149: inline Builder(unsigned short value); cannam@149: inline Builder(unsigned int value); cannam@149: inline Builder(unsigned long value); cannam@149: inline Builder(unsigned long long value); cannam@149: inline Builder(float value); cannam@149: inline Builder(double value); cannam@149: inline Builder(Text::Builder value); cannam@149: inline Builder(Data::Builder value); cannam@149: inline Builder(DynamicList::Builder value); cannam@149: inline Builder(DynamicEnum value); cannam@149: inline Builder(DynamicStruct::Builder value); cannam@149: inline Builder(AnyPointer::Builder value); cannam@149: inline Builder(DynamicCapability::Client& value); cannam@149: inline Builder(DynamicCapability::Client&& value); cannam@149: cannam@149: template ()))> cannam@149: inline Builder(T value): Builder(toDynamic(value)) {} cannam@149: cannam@149: Builder(Builder& other); cannam@149: Builder(Builder&& other) noexcept; cannam@149: ~Builder() noexcept(false); cannam@149: Builder& operator=(Builder& other); cannam@149: Builder& operator=(Builder&& other); cannam@149: // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not cannam@149: // trivially copyable. cannam@149: cannam@149: template cannam@149: inline BuilderFor as() { return AsImpl::apply(*this); } cannam@149: // See DynamicValue::Reader::as(). cannam@149: cannam@149: inline Type getType() { return type; } cannam@149: // Get the type of this value. cannam@149: cannam@149: Reader asReader() const; cannam@149: cannam@149: private: cannam@149: Type type; cannam@149: cannam@149: union { cannam@149: Void voidValue; cannam@149: bool boolValue; cannam@149: int64_t intValue; cannam@149: uint64_t uintValue; cannam@149: double floatValue; cannam@149: Text::Builder textValue; cannam@149: Data::Builder dataValue; cannam@149: DynamicList::Builder listValue; cannam@149: DynamicEnum enumValue; cannam@149: DynamicStruct::Builder structValue; cannam@149: AnyPointer::Builder anyPointerValue; cannam@149: cannam@149: mutable DynamicCapability::Client capabilityValue; cannam@149: // Declared mutable because `Client`s normally cannot be const. cannam@149: }; cannam@149: cannam@149: template ()> struct AsImpl; cannam@149: // Implementation backing the as() method. Needs to be a struct to allow partial cannam@149: // specialization. Has a method apply() which does the work. cannam@149: cannam@149: friend class Orphan; cannam@149: }; cannam@149: cannam@149: class DynamicValue::Pipeline { cannam@149: public: cannam@149: typedef DynamicValue Pipelines; cannam@149: cannam@149: inline Pipeline(decltype(nullptr) n = nullptr); cannam@149: inline Pipeline(DynamicStruct::Pipeline&& value); cannam@149: inline Pipeline(DynamicCapability::Client&& value); cannam@149: cannam@149: Pipeline(Pipeline&& other) noexcept; cannam@149: Pipeline& operator=(Pipeline&& other); cannam@149: ~Pipeline() noexcept(false); cannam@149: cannam@149: template cannam@149: inline PipelineFor releaseAs() { return AsImpl::apply(*this); } cannam@149: cannam@149: inline Type getType() { return type; } cannam@149: // Get the type of this value. cannam@149: cannam@149: private: cannam@149: Type type; cannam@149: union { cannam@149: DynamicStruct::Pipeline structValue; cannam@149: DynamicCapability::Client capabilityValue; cannam@149: }; cannam@149: cannam@149: template ()> struct AsImpl; cannam@149: // Implementation backing the releaseAs() method. Needs to be a struct to allow partial cannam@149: // specialization. Has a method apply() which does the work. cannam@149: }; cannam@149: cannam@149: kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value); cannam@149: kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value); cannam@149: kj::StringTree KJ_STRINGIFY(DynamicEnum value); cannam@149: kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value); cannam@149: kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value); cannam@149: kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value); cannam@149: kj::StringTree KJ_STRINGIFY(const DynamicList::Builder& value); cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: // Orphan <-> Dynamic glue cannam@149: cannam@149: template <> cannam@149: class Orphan { cannam@149: public: cannam@149: Orphan() = default; cannam@149: KJ_DISALLOW_COPY(Orphan); cannam@149: Orphan(Orphan&&) = default; cannam@149: Orphan& operator=(Orphan&&) = default; cannam@149: cannam@149: template () == Kind::STRUCT>> cannam@149: inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} cannam@149: cannam@149: DynamicStruct::Builder get(); cannam@149: DynamicStruct::Reader getReader() const; cannam@149: cannam@149: template cannam@149: Orphan releaseAs(); cannam@149: // Like DynamicStruct::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, cannam@149: // the original Orphan is no longer valid after this call; ownership is cannam@149: // transferred to the returned Orphan. cannam@149: cannam@149: inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } cannam@149: inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } cannam@149: cannam@149: private: cannam@149: StructSchema schema; cannam@149: _::OrphanBuilder builder; cannam@149: cannam@149: inline Orphan(StructSchema schema, _::OrphanBuilder&& builder) cannam@149: : schema(schema), builder(kj::mv(builder)) {} cannam@149: cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: friend struct DynamicList; cannam@149: friend class Orphanage; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: friend class MessageBuilder; cannam@149: }; cannam@149: cannam@149: template <> cannam@149: class Orphan { cannam@149: public: cannam@149: Orphan() = default; cannam@149: KJ_DISALLOW_COPY(Orphan); cannam@149: Orphan(Orphan&&) = default; cannam@149: Orphan& operator=(Orphan&&) = default; cannam@149: cannam@149: template () == Kind::LIST>> cannam@149: inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} cannam@149: cannam@149: DynamicList::Builder get(); cannam@149: DynamicList::Reader getReader() const; cannam@149: cannam@149: template cannam@149: Orphan releaseAs(); cannam@149: // Like DynamicList::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, cannam@149: // the original Orphan is no longer valid after this call; ownership is cannam@149: // transferred to the returned Orphan. cannam@149: cannam@149: // TODO(someday): Support truncate(). cannam@149: cannam@149: inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } cannam@149: inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } cannam@149: cannam@149: private: cannam@149: ListSchema schema; cannam@149: _::OrphanBuilder builder; cannam@149: cannam@149: inline Orphan(ListSchema schema, _::OrphanBuilder&& builder) cannam@149: : schema(schema), builder(kj::mv(builder)) {} cannam@149: cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: friend struct DynamicList; cannam@149: friend class Orphanage; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: }; cannam@149: cannam@149: template <> cannam@149: class Orphan { cannam@149: public: cannam@149: Orphan() = default; cannam@149: KJ_DISALLOW_COPY(Orphan); cannam@149: Orphan(Orphan&&) = default; cannam@149: Orphan& operator=(Orphan&&) = default; cannam@149: cannam@149: template () == Kind::INTERFACE>> cannam@149: inline Orphan(Orphan&& other): schema(Schema::from()), builder(kj::mv(other.builder)) {} cannam@149: cannam@149: DynamicCapability::Client get(); cannam@149: DynamicCapability::Client getReader() const; cannam@149: cannam@149: template cannam@149: Orphan releaseAs(); cannam@149: // Like DynamicCapability::Client::as(), but coerces the Orphan type. Since Orphans are move-only, cannam@149: // the original Orphan is no longer valid after this call; ownership is cannam@149: // transferred to the returned Orphan. cannam@149: cannam@149: inline bool operator==(decltype(nullptr)) const { return builder == nullptr; } cannam@149: inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; } cannam@149: cannam@149: private: cannam@149: InterfaceSchema schema; cannam@149: _::OrphanBuilder builder; cannam@149: cannam@149: inline Orphan(InterfaceSchema schema, _::OrphanBuilder&& builder) cannam@149: : schema(schema), builder(kj::mv(builder)) {} cannam@149: cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: friend struct DynamicList; cannam@149: friend class Orphanage; cannam@149: friend class Orphan; cannam@149: friend class Orphan; cannam@149: }; cannam@149: cannam@149: template <> cannam@149: class Orphan { cannam@149: public: cannam@149: inline Orphan(decltype(nullptr) n = nullptr): type(DynamicValue::UNKNOWN) {} cannam@149: inline Orphan(Void value); cannam@149: inline Orphan(bool value); cannam@149: inline Orphan(char value); cannam@149: inline Orphan(signed char value); cannam@149: inline Orphan(short value); cannam@149: inline Orphan(int value); cannam@149: inline Orphan(long value); cannam@149: inline Orphan(long long value); cannam@149: inline Orphan(unsigned char value); cannam@149: inline Orphan(unsigned short value); cannam@149: inline Orphan(unsigned int value); cannam@149: inline Orphan(unsigned long value); cannam@149: inline Orphan(unsigned long long value); cannam@149: inline Orphan(float value); cannam@149: inline Orphan(double value); cannam@149: inline Orphan(DynamicEnum value); cannam@149: Orphan(Orphan&&) = default; cannam@149: template cannam@149: Orphan(Orphan&&); cannam@149: Orphan(Orphan&&); cannam@149: Orphan(void*) = delete; // So Orphan(bool) doesn't accept pointers. cannam@149: KJ_DISALLOW_COPY(Orphan); cannam@149: cannam@149: Orphan& operator=(Orphan&&) = default; cannam@149: cannam@149: inline DynamicValue::Type getType() { return type; } cannam@149: cannam@149: DynamicValue::Builder get(); cannam@149: DynamicValue::Reader getReader() const; cannam@149: cannam@149: template cannam@149: Orphan releaseAs(); cannam@149: // Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only, cannam@149: // the original Orphan is no longer valid after this call; ownership is cannam@149: // transferred to the returned Orphan. cannam@149: cannam@149: private: cannam@149: DynamicValue::Type type; cannam@149: union { cannam@149: Void voidValue; cannam@149: bool boolValue; cannam@149: int64_t intValue; cannam@149: uint64_t uintValue; cannam@149: double floatValue; cannam@149: DynamicEnum enumValue; cannam@149: StructSchema structSchema; cannam@149: ListSchema listSchema; cannam@149: InterfaceSchema interfaceSchema; cannam@149: }; cannam@149: cannam@149: _::OrphanBuilder builder; cannam@149: // Only used if `type` is a pointer type. cannam@149: cannam@149: Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder); cannam@149: Orphan(DynamicValue::Type type, _::OrphanBuilder&& builder) cannam@149: : type(type), builder(kj::mv(builder)) {} cannam@149: Orphan(StructSchema structSchema, _::OrphanBuilder&& builder) cannam@149: : type(DynamicValue::STRUCT), structSchema(structSchema), builder(kj::mv(builder)) {} cannam@149: Orphan(ListSchema listSchema, _::OrphanBuilder&& builder) cannam@149: : type(DynamicValue::LIST), listSchema(listSchema), builder(kj::mv(builder)) {} cannam@149: cannam@149: template cannam@149: friend struct _::PointerHelpers; cannam@149: friend struct DynamicStruct; cannam@149: friend struct DynamicList; cannam@149: friend struct AnyPointer; cannam@149: friend class Orphanage; cannam@149: }; cannam@149: cannam@149: template cannam@149: inline Orphan::Orphan(Orphan&& other) cannam@149: : Orphan(other.get(), kj::mv(other.builder)) {} cannam@149: cannam@149: inline Orphan::Orphan(Orphan&& other) cannam@149: : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {} cannam@149: cannam@149: template cannam@149: Orphan Orphan::releaseAs() { cannam@149: get().as(); // type check cannam@149: return Orphan(kj::mv(builder)); cannam@149: } cannam@149: cannam@149: template cannam@149: Orphan Orphan::releaseAs() { cannam@149: get().as(); // type check cannam@149: return Orphan(kj::mv(builder)); cannam@149: } cannam@149: cannam@149: template cannam@149: Orphan Orphan::releaseAs() { cannam@149: get().as(); // type check cannam@149: return Orphan(kj::mv(builder)); cannam@149: } cannam@149: cannam@149: template cannam@149: Orphan Orphan::releaseAs() { cannam@149: get().as(); // type check cannam@149: type = DynamicValue::UNKNOWN; cannam@149: return Orphan(kj::mv(builder)); cannam@149: } cannam@149: cannam@149: template <> cannam@149: Orphan Orphan::releaseAs(); cannam@149: template <> cannam@149: Orphan Orphan::releaseAs(); cannam@149: template <> cannam@149: Orphan Orphan::releaseAs(); cannam@149: template <> cannam@149: Orphan Orphan::releaseAs(); cannam@149: cannam@149: template <> cannam@149: struct Orphanage::GetInnerBuilder { cannam@149: static inline _::StructBuilder apply(DynamicStruct::Builder& t) { cannam@149: return t.builder; cannam@149: } cannam@149: }; cannam@149: cannam@149: template <> cannam@149: struct Orphanage::GetInnerBuilder { cannam@149: static inline _::ListBuilder apply(DynamicList::Builder& t) { cannam@149: return t.builder; cannam@149: } cannam@149: }; cannam@149: cannam@149: template <> cannam@149: inline Orphan Orphanage::newOrphanCopy( cannam@149: DynamicStruct::Reader copyFrom) const { cannam@149: return Orphan( cannam@149: copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline Orphan Orphanage::newOrphanCopy( cannam@149: DynamicList::Reader copyFrom) const { cannam@149: return Orphan(copyFrom.getSchema(), cannam@149: _::OrphanBuilder::copy(arena, capTable, copyFrom.reader)); cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline Orphan Orphanage::newOrphanCopy( cannam@149: DynamicCapability::Client copyFrom) const { cannam@149: return Orphan( cannam@149: copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef())); cannam@149: } cannam@149: cannam@149: template <> cannam@149: Orphan Orphanage::newOrphanCopy( cannam@149: DynamicValue::Reader copyFrom) const; cannam@149: cannam@149: namespace _ { // private cannam@149: cannam@149: template <> cannam@149: struct PointerHelpers { cannam@149: // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for cannam@149: // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we cannam@149: // don't want people to accidentally be able to provide their own default value. cannam@149: static DynamicStruct::Reader getDynamic(PointerReader reader, StructSchema schema); cannam@149: static DynamicStruct::Builder getDynamic(PointerBuilder builder, StructSchema schema); cannam@149: static void set(PointerBuilder builder, const DynamicStruct::Reader& value); cannam@149: static DynamicStruct::Builder init(PointerBuilder builder, StructSchema schema); cannam@149: static inline void adopt(PointerBuilder builder, Orphan&& value) { cannam@149: builder.adopt(kj::mv(value.builder)); cannam@149: } cannam@149: static inline Orphan disown(PointerBuilder builder, StructSchema schema) { cannam@149: return Orphan(schema, builder.disown()); cannam@149: } cannam@149: }; cannam@149: cannam@149: template <> cannam@149: struct PointerHelpers { cannam@149: // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for cannam@149: // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we cannam@149: // don't want people to accidentally be able to provide their own default value. cannam@149: static DynamicList::Reader getDynamic(PointerReader reader, ListSchema schema); cannam@149: static DynamicList::Builder getDynamic(PointerBuilder builder, ListSchema schema); cannam@149: static void set(PointerBuilder builder, const DynamicList::Reader& value); cannam@149: static DynamicList::Builder init(PointerBuilder builder, ListSchema schema, uint size); cannam@149: static inline void adopt(PointerBuilder builder, Orphan&& value) { cannam@149: builder.adopt(kj::mv(value.builder)); cannam@149: } cannam@149: static inline Orphan disown(PointerBuilder builder, ListSchema schema) { cannam@149: return Orphan(schema, builder.disown()); cannam@149: } cannam@149: }; cannam@149: cannam@149: template <> cannam@149: struct PointerHelpers { cannam@149: // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for cannam@149: // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we cannam@149: // don't want people to accidentally be able to provide their own default value. cannam@149: static DynamicCapability::Client getDynamic(PointerReader reader, InterfaceSchema schema); cannam@149: static DynamicCapability::Client getDynamic(PointerBuilder builder, InterfaceSchema schema); cannam@149: static void set(PointerBuilder builder, DynamicCapability::Client& value); cannam@149: static void set(PointerBuilder builder, DynamicCapability::Client&& value); cannam@149: static inline void adopt(PointerBuilder builder, Orphan&& value) { cannam@149: builder.adopt(kj::mv(value.builder)); cannam@149: } cannam@149: static inline Orphan disown(PointerBuilder builder, InterfaceSchema schema) { cannam@149: return Orphan(schema, builder.disown()); cannam@149: } cannam@149: }; cannam@149: cannam@149: } // namespace _ (private) cannam@149: cannam@149: template cannam@149: inline ReaderFor AnyPointer::Reader::getAs(StructSchema schema) const { cannam@149: return _::PointerHelpers::getDynamic(reader, schema); cannam@149: } cannam@149: template cannam@149: inline ReaderFor AnyPointer::Reader::getAs(ListSchema schema) const { cannam@149: return _::PointerHelpers::getDynamic(reader, schema); cannam@149: } cannam@149: template cannam@149: inline ReaderFor AnyPointer::Reader::getAs(InterfaceSchema schema) const { cannam@149: return _::PointerHelpers::getDynamic(reader, schema); cannam@149: } cannam@149: template cannam@149: inline BuilderFor AnyPointer::Builder::getAs(StructSchema schema) { cannam@149: return _::PointerHelpers::getDynamic(builder, schema); cannam@149: } cannam@149: template cannam@149: inline BuilderFor AnyPointer::Builder::getAs(ListSchema schema) { cannam@149: return _::PointerHelpers::getDynamic(builder, schema); cannam@149: } cannam@149: template cannam@149: inline BuilderFor AnyPointer::Builder::getAs(InterfaceSchema schema) { cannam@149: return _::PointerHelpers::getDynamic(builder, schema); cannam@149: } cannam@149: template cannam@149: inline BuilderFor AnyPointer::Builder::initAs(StructSchema schema) { cannam@149: return _::PointerHelpers::init(builder, schema); cannam@149: } cannam@149: template cannam@149: inline BuilderFor AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) { cannam@149: return _::PointerHelpers::init(builder, schema, elementCount); cannam@149: } cannam@149: template <> cannam@149: inline void AnyPointer::Builder::setAs(DynamicStruct::Reader value) { cannam@149: return _::PointerHelpers::set(builder, value); cannam@149: } cannam@149: template <> cannam@149: inline void AnyPointer::Builder::setAs(DynamicList::Reader value) { cannam@149: return _::PointerHelpers::set(builder, value); cannam@149: } cannam@149: template <> cannam@149: inline void AnyPointer::Builder::setAs(DynamicCapability::Client value) { cannam@149: return _::PointerHelpers::set(builder, kj::mv(value)); cannam@149: } cannam@149: template <> cannam@149: void AnyPointer::Builder::adopt(Orphan&& orphan); cannam@149: template cannam@149: inline Orphan AnyPointer::Builder::disownAs(StructSchema schema) { cannam@149: return _::PointerHelpers::disown(builder, schema); cannam@149: } cannam@149: template cannam@149: inline Orphan AnyPointer::Builder::disownAs(ListSchema schema) { cannam@149: return _::PointerHelpers::disown(builder, schema); cannam@149: } cannam@149: template cannam@149: inline Orphan AnyPointer::Builder::disownAs(InterfaceSchema schema) { cannam@149: return _::PointerHelpers::disown(builder, schema); cannam@149: } cannam@149: cannam@149: // We have to declare the methods below inline because Clang and GCC disagree about how to mangle cannam@149: // their symbol names. cannam@149: template <> cannam@149: inline DynamicStruct::Builder Orphan::getAs(StructSchema schema) { cannam@149: return DynamicStruct::Builder(schema, builder); cannam@149: } cannam@149: template <> cannam@149: inline DynamicStruct::Reader Orphan::getAsReader( cannam@149: StructSchema schema) const { cannam@149: return DynamicStruct::Reader(schema, builder); cannam@149: } cannam@149: template <> cannam@149: inline Orphan Orphan::releaseAs(StructSchema schema) { cannam@149: return Orphan(schema, kj::mv(builder)); cannam@149: } cannam@149: template <> cannam@149: inline DynamicList::Builder Orphan::getAs(ListSchema schema) { cannam@149: return DynamicList::Builder(schema, builder); cannam@149: } cannam@149: template <> cannam@149: inline DynamicList::Reader Orphan::getAsReader(ListSchema schema) const { cannam@149: return DynamicList::Reader(schema, builder); cannam@149: } cannam@149: template <> cannam@149: inline Orphan Orphan::releaseAs(ListSchema schema) { cannam@149: return Orphan(schema, kj::mv(builder)); cannam@149: } cannam@149: template <> cannam@149: inline DynamicCapability::Client Orphan::getAs( cannam@149: InterfaceSchema schema) { cannam@149: return DynamicCapability::Client(schema, builder.asCapability()); cannam@149: } cannam@149: template <> cannam@149: inline DynamicCapability::Client Orphan::getAsReader( cannam@149: InterfaceSchema schema) const { cannam@149: return DynamicCapability::Client(schema, builder.asCapability()); cannam@149: } cannam@149: template <> cannam@149: inline Orphan Orphan::releaseAs( cannam@149: InterfaceSchema schema) { cannam@149: return Orphan(schema, kj::mv(builder)); cannam@149: } cannam@149: cannam@149: // ======================================================================================= cannam@149: // Inline implementation details. cannam@149: cannam@149: template cannam@149: struct ToDynamic_ { cannam@149: static inline DynamicStruct::Reader apply(const typename T::Reader& value) { cannam@149: return DynamicStruct::Reader(Schema::from(), value._reader); cannam@149: } cannam@149: static inline DynamicStruct::Builder apply(typename T::Builder& value) { cannam@149: return DynamicStruct::Builder(Schema::from(), value._builder); cannam@149: } cannam@149: }; cannam@149: cannam@149: template cannam@149: struct ToDynamic_ { cannam@149: static inline DynamicList::Reader apply(const typename T::Reader& value) { cannam@149: return DynamicList::Reader(Schema::from(), value.reader); cannam@149: } cannam@149: static inline DynamicList::Builder apply(typename T::Builder& value) { cannam@149: return DynamicList::Builder(Schema::from(), value.builder); cannam@149: } cannam@149: }; cannam@149: cannam@149: template cannam@149: struct ToDynamic_ { cannam@149: static inline DynamicCapability::Client apply(typename T::Client value) { cannam@149: return DynamicCapability::Client(kj::mv(value)); cannam@149: } cannam@149: static inline DynamicCapability::Client apply(typename T::Client&& value) { cannam@149: return DynamicCapability::Client(kj::mv(value)); cannam@149: } cannam@149: }; cannam@149: cannam@149: template cannam@149: ReaderFor>> toDynamic(T&& value) { cannam@149: return ToDynamic_>::apply(value); cannam@149: } cannam@149: template cannam@149: BuilderFor>> toDynamic(T&& value) { cannam@149: return ToDynamic_>::apply(value); cannam@149: } cannam@149: template cannam@149: DynamicTypeFor> toDynamic(T&& value) { cannam@149: return DynamicEnum(Schema::from>(), static_cast(value)); cannam@149: } cannam@149: template cannam@149: typename DynamicTypeFor>::Client toDynamic(kj::Own&& value) { cannam@149: return typename FromServer::Client(kj::mv(value)); cannam@149: } cannam@149: cannam@149: inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {} cannam@149: inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {} cannam@149: cannam@149: #define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ cannam@149: inline DynamicValue::Reader::Reader(cppType value) \ cannam@149: : type(typeTag), fieldName##Value(value) {} \ cannam@149: inline DynamicValue::Builder::Builder(cppType value) \ cannam@149: : type(typeTag), fieldName##Value(value) {} \ cannam@149: inline Orphan::Orphan(cppType value) \ cannam@149: : type(DynamicValue::typeTag), fieldName##Value(value) {} cannam@149: cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Void, VOID, void); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(bool, BOOL, bool); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(char, INT, int); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(signed char, INT, int); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(short, INT, int); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(int, INT, int); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long, INT, int); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long long, INT, int); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned char, UINT, uint); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned short, UINT, uint); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned int, UINT, uint); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long, UINT, uint); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum); cannam@149: #undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR cannam@149: cannam@149: #define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \ cannam@149: inline DynamicValue::Reader::Reader(const cppType::Reader& value) \ cannam@149: : type(typeTag), fieldName##Value(value) {} \ cannam@149: inline DynamicValue::Builder::Builder(cppType::Builder value) \ cannam@149: : type(typeTag), fieldName##Value(value) {} cannam@149: cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct); cannam@149: CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer); cannam@149: cannam@149: #undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR cannam@149: cannam@149: inline DynamicValue::Reader::Reader(DynamicCapability::Client& value) cannam@149: : type(CAPABILITY), capabilityValue(value) {} cannam@149: inline DynamicValue::Reader::Reader(DynamicCapability::Client&& value) cannam@149: : type(CAPABILITY), capabilityValue(kj::mv(value)) {} cannam@149: template cannam@149: inline DynamicValue::Reader::Reader(kj::Own&& value) cannam@149: : type(CAPABILITY), capabilityValue(kj::mv(value)) {} cannam@149: inline DynamicValue::Builder::Builder(DynamicCapability::Client& value) cannam@149: : type(CAPABILITY), capabilityValue(value) {} cannam@149: inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value) cannam@149: : type(CAPABILITY), capabilityValue(kj::mv(value)) {} cannam@149: cannam@149: inline DynamicValue::Reader::Reader(const char* value): Reader(Text::Reader(value)) {} cannam@149: cannam@149: #define CAPNP_DECLARE_TYPE(discrim, typeName) \ cannam@149: template <> \ cannam@149: struct DynamicValue::Reader::AsImpl { \ cannam@149: static ReaderFor apply(const Reader& reader); \ cannam@149: }; \ cannam@149: template <> \ cannam@149: struct DynamicValue::Builder::AsImpl { \ cannam@149: static BuilderFor apply(Builder& builder); \ cannam@149: }; cannam@149: cannam@149: //CAPNP_DECLARE_TYPE(VOID, Void) cannam@149: CAPNP_DECLARE_TYPE(BOOL, bool) cannam@149: CAPNP_DECLARE_TYPE(INT8, int8_t) cannam@149: CAPNP_DECLARE_TYPE(INT16, int16_t) cannam@149: CAPNP_DECLARE_TYPE(INT32, int32_t) cannam@149: CAPNP_DECLARE_TYPE(INT64, int64_t) cannam@149: CAPNP_DECLARE_TYPE(UINT8, uint8_t) cannam@149: CAPNP_DECLARE_TYPE(UINT16, uint16_t) cannam@149: CAPNP_DECLARE_TYPE(UINT32, uint32_t) cannam@149: CAPNP_DECLARE_TYPE(UINT64, uint64_t) cannam@149: CAPNP_DECLARE_TYPE(FLOAT32, float) cannam@149: CAPNP_DECLARE_TYPE(FLOAT64, double) cannam@149: cannam@149: CAPNP_DECLARE_TYPE(TEXT, Text) cannam@149: CAPNP_DECLARE_TYPE(DATA, Data) cannam@149: CAPNP_DECLARE_TYPE(LIST, DynamicList) cannam@149: CAPNP_DECLARE_TYPE(STRUCT, DynamicStruct) cannam@149: CAPNP_DECLARE_TYPE(INTERFACE, DynamicCapability) cannam@149: CAPNP_DECLARE_TYPE(ENUM, DynamicEnum) cannam@149: CAPNP_DECLARE_TYPE(ANY_POINTER, AnyPointer) cannam@149: #undef CAPNP_DECLARE_TYPE cannam@149: cannam@149: // CAPNP_DECLARE_TYPE(Void) causes gcc 4.7 to segfault. If I do it manually and remove the cannam@149: // ReaderFor<> and BuilderFor<> wrappers, it works. cannam@149: template <> cannam@149: struct DynamicValue::Reader::AsImpl { cannam@149: static Void apply(const Reader& reader); cannam@149: }; cannam@149: template <> cannam@149: struct DynamicValue::Builder::AsImpl { cannam@149: static Void apply(Builder& builder); cannam@149: }; cannam@149: cannam@149: template cannam@149: struct DynamicValue::Reader::AsImpl { cannam@149: static T apply(const Reader& reader) { cannam@149: return reader.as().as(); cannam@149: } cannam@149: }; cannam@149: template cannam@149: struct DynamicValue::Builder::AsImpl { cannam@149: static T apply(Builder& builder) { cannam@149: return builder.as().as(); cannam@149: } cannam@149: }; cannam@149: cannam@149: template cannam@149: struct DynamicValue::Reader::AsImpl { cannam@149: static typename T::Reader apply(const Reader& reader) { cannam@149: return reader.as().as(); cannam@149: } cannam@149: }; cannam@149: template cannam@149: struct DynamicValue::Builder::AsImpl { cannam@149: static typename T::Builder apply(Builder& builder) { cannam@149: return builder.as().as(); cannam@149: } cannam@149: }; cannam@149: cannam@149: template cannam@149: struct DynamicValue::Reader::AsImpl { cannam@149: static typename T::Reader apply(const Reader& reader) { cannam@149: return reader.as().as(); cannam@149: } cannam@149: }; cannam@149: template cannam@149: struct DynamicValue::Builder::AsImpl { cannam@149: static typename T::Builder apply(Builder& builder) { cannam@149: return builder.as().as(); cannam@149: } cannam@149: }; cannam@149: cannam@149: template cannam@149: struct DynamicValue::Reader::AsImpl { cannam@149: static typename T::Client apply(const Reader& reader) { cannam@149: return reader.as().as(); cannam@149: } cannam@149: }; cannam@149: template cannam@149: struct DynamicValue::Builder::AsImpl { cannam@149: static typename T::Client apply(Builder& builder) { cannam@149: return builder.as().as(); cannam@149: } cannam@149: }; cannam@149: cannam@149: template <> cannam@149: struct DynamicValue::Reader::AsImpl { cannam@149: static DynamicValue::Reader apply(const Reader& reader) { cannam@149: return reader; cannam@149: } cannam@149: }; cannam@149: template <> cannam@149: struct DynamicValue::Builder::AsImpl { cannam@149: static DynamicValue::Builder apply(Builder& builder) { cannam@149: return builder; cannam@149: } cannam@149: }; cannam@149: cannam@149: inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {} cannam@149: inline DynamicValue::Pipeline::Pipeline(DynamicStruct::Pipeline&& value) cannam@149: : type(STRUCT), structValue(kj::mv(value)) {} cannam@149: inline DynamicValue::Pipeline::Pipeline(DynamicCapability::Client&& value) cannam@149: : type(CAPABILITY), capabilityValue(kj::mv(value)) {} cannam@149: cannam@149: template cannam@149: struct DynamicValue::Pipeline::AsImpl { cannam@149: static typename T::Pipeline apply(Pipeline& pipeline) { cannam@149: return pipeline.releaseAs().releaseAs(); cannam@149: } cannam@149: }; cannam@149: template cannam@149: struct DynamicValue::Pipeline::AsImpl { cannam@149: static typename T::Client apply(Pipeline& pipeline) { cannam@149: return pipeline.releaseAs().releaseAs(); cannam@149: } cannam@149: }; cannam@149: template <> cannam@149: struct DynamicValue::Pipeline::AsImpl { cannam@149: static PipelineFor apply(Pipeline& pipeline); cannam@149: }; cannam@149: template <> cannam@149: struct DynamicValue::Pipeline::AsImpl { cannam@149: static PipelineFor apply(Pipeline& pipeline); cannam@149: }; cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: template cannam@149: typename T::Reader DynamicStruct::Reader::as() const { cannam@149: static_assert(kind() == Kind::STRUCT, cannam@149: "DynamicStruct::Reader::as() can only convert to struct types."); cannam@149: schema.requireUsableAs(); cannam@149: return typename T::Reader(reader); cannam@149: } cannam@149: cannam@149: template cannam@149: typename T::Builder DynamicStruct::Builder::as() { cannam@149: static_assert(kind() == Kind::STRUCT, cannam@149: "DynamicStruct::Builder::as() can only convert to struct types."); cannam@149: schema.requireUsableAs(); cannam@149: return typename T::Builder(builder); cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline DynamicStruct::Reader DynamicStruct::Reader::as() const { cannam@149: return *this; cannam@149: } cannam@149: template <> cannam@149: inline DynamicStruct::Builder DynamicStruct::Builder::as() { cannam@149: return *this; cannam@149: } cannam@149: cannam@149: inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const { cannam@149: return DynamicStruct::Reader(schema, builder.asReader()); cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline AnyStruct::Reader DynamicStruct::Reader::as() const { cannam@149: return AnyStruct::Reader(reader); cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline AnyStruct::Builder DynamicStruct::Builder::as() { cannam@149: return AnyStruct::Builder(builder); cannam@149: } cannam@149: cannam@149: template cannam@149: typename T::Pipeline DynamicStruct::Pipeline::releaseAs() { cannam@149: static_assert(kind() == Kind::STRUCT, cannam@149: "DynamicStruct::Pipeline::releaseAs() can only convert to struct types."); cannam@149: schema.requireUsableAs(); cannam@149: return typename T::Pipeline(kj::mv(typeless)); cannam@149: } cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: template cannam@149: typename T::Reader DynamicList::Reader::as() const { cannam@149: static_assert(kind() == Kind::LIST, cannam@149: "DynamicStruct::Reader::as() can only convert to list types."); cannam@149: schema.requireUsableAs(); cannam@149: return typename T::Reader(reader); cannam@149: } cannam@149: template cannam@149: typename T::Builder DynamicList::Builder::as() { cannam@149: static_assert(kind() == Kind::LIST, cannam@149: "DynamicStruct::Builder::as() can only convert to list types."); cannam@149: schema.requireUsableAs(); cannam@149: return typename T::Builder(builder); cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline DynamicList::Reader DynamicList::Reader::as() const { cannam@149: return *this; cannam@149: } cannam@149: template <> cannam@149: inline DynamicList::Builder DynamicList::Builder::as() { cannam@149: return *this; cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline AnyList::Reader DynamicList::Reader::as() const { cannam@149: return AnyList::Reader(reader); cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline AnyList::Builder DynamicList::Builder::as() { cannam@149: return AnyList::Builder(builder); cannam@149: } cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: template cannam@149: inline DynamicCapability::Client::Client(T&& client) cannam@149: : Capability::Client(kj::mv(client)), schema(Schema::from>()) {} cannam@149: cannam@149: template cannam@149: inline DynamicCapability::Client::Client(kj::Own&& server) cannam@149: : Client(server->getSchema(), kj::mv(server)) {} cannam@149: template cannam@149: inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own&& server) cannam@149: : Capability::Client(kj::mv(server)), schema(schema) {} cannam@149: cannam@149: template cannam@149: typename T::Client DynamicCapability::Client::as() { cannam@149: static_assert(kind() == Kind::INTERFACE, cannam@149: "DynamicCapability::Client::as() can only convert to interface types."); cannam@149: schema.requireUsableAs(); cannam@149: return typename T::Client(hook->addRef()); cannam@149: } cannam@149: cannam@149: template cannam@149: typename T::Client DynamicCapability::Client::releaseAs() { cannam@149: static_assert(kind() == Kind::INTERFACE, cannam@149: "DynamicCapability::Client::as() can only convert to interface types."); cannam@149: schema.requireUsableAs(); cannam@149: return typename T::Client(kj::mv(hook)); cannam@149: } cannam@149: cannam@149: inline CallContext::CallContext( cannam@149: CallContextHook& hook, StructSchema paramType, StructSchema resultType) cannam@149: : hook(&hook), paramType(paramType), resultType(resultType) {} cannam@149: inline DynamicStruct::Reader CallContext::getParams() { cannam@149: return hook->getParams().getAs(paramType); cannam@149: } cannam@149: inline void CallContext::releaseParams() { cannam@149: hook->releaseParams(); cannam@149: } cannam@149: inline DynamicStruct::Builder CallContext::getResults( cannam@149: kj::Maybe sizeHint) { cannam@149: return hook->getResults(sizeHint).getAs(resultType); cannam@149: } cannam@149: inline DynamicStruct::Builder CallContext::initResults( cannam@149: kj::Maybe sizeHint) { cannam@149: return hook->getResults(sizeHint).initAs(resultType); cannam@149: } cannam@149: inline void CallContext::setResults(DynamicStruct::Reader value) { cannam@149: hook->getResults(value.totalSize()).setAs(value); cannam@149: } cannam@149: inline void CallContext::adoptResults(Orphan&& value) { cannam@149: hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value)); cannam@149: } cannam@149: inline Orphanage CallContext::getResultsOrphanage( cannam@149: kj::Maybe sizeHint) { cannam@149: return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); cannam@149: } cannam@149: template cannam@149: inline kj::Promise CallContext::tailCall( cannam@149: Request&& tailRequest) { cannam@149: return hook->tailCall(kj::mv(tailRequest.hook)); cannam@149: } cannam@149: inline void CallContext::allowCancellation() { cannam@149: hook->allowCancellation(); cannam@149: } cannam@149: cannam@149: template <> cannam@149: inline DynamicCapability::Client Capability::Client::castAs( cannam@149: InterfaceSchema schema) { cannam@149: return DynamicCapability::Client(schema, hook->addRef()); cannam@149: } cannam@149: cannam@149: // ------------------------------------------------------------------- cannam@149: cannam@149: template cannam@149: ReaderFor ConstSchema::as() const { cannam@149: return DynamicValue::Reader(*this).as(); cannam@149: } cannam@149: cannam@149: } // namespace capnp cannam@149: cannam@149: #endif // CAPNP_DYNAMIC_H_