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.
		
		
		
		
		
			
		
			
				
					
					
						
							934 lines
						
					
					
						
							35 KiB
						
					
					
				
			
		
		
	
	
							934 lines
						
					
					
						
							35 KiB
						
					
					
				| // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
 | |
| // Licensed under the MIT License:
 | |
| //
 | |
| // Permission is hereby granted, free of charge, to any person obtaining a copy
 | |
| // of this software and associated documentation files (the "Software"), to deal
 | |
| // in the Software without restriction, including without limitation the rights
 | |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | |
| // copies of the Software, and to permit persons to whom the Software is
 | |
| // furnished to do so, subject to the following conditions:
 | |
| //
 | |
| // The above copyright notice and this permission notice shall be included in
 | |
| // all copies or substantial portions of the Software.
 | |
| //
 | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | |
| // THE SOFTWARE.
 | |
| 
 | |
| #ifndef CAPNP_SCHEMA_H_
 | |
| #define CAPNP_SCHEMA_H_
 | |
| 
 | |
| #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
 | |
| #pragma GCC system_header
 | |
| #endif
 | |
| 
 | |
| #if CAPNP_LITE
 | |
| #error "Reflection APIs, including this header, are not available in lite mode."
 | |
| #endif
 | |
| 
 | |
| #include <capnp/schema.capnp.h>
 | |
| 
 | |
| namespace capnp {
 | |
| 
 | |
| class Schema;
 | |
| class StructSchema;
 | |
| class EnumSchema;
 | |
| class InterfaceSchema;
 | |
| class ConstSchema;
 | |
| class ListSchema;
 | |
| class Type;
 | |
| 
 | |
| template <typename T, Kind k = kind<T>()> struct SchemaType_ { typedef Schema Type; };
 | |
| template <typename T> struct SchemaType_<T, Kind::PRIMITIVE> { typedef schema::Type::Which Type; };
 | |
| template <typename T> struct SchemaType_<T, Kind::BLOB> { typedef schema::Type::Which Type; };
 | |
| template <typename T> struct SchemaType_<T, Kind::ENUM> { typedef EnumSchema Type; };
 | |
| template <typename T> struct SchemaType_<T, Kind::STRUCT> { typedef StructSchema Type; };
 | |
| template <typename T> struct SchemaType_<T, Kind::INTERFACE> { typedef InterfaceSchema Type; };
 | |
| template <typename T> struct SchemaType_<T, Kind::LIST> { typedef ListSchema Type; };
 | |
| 
 | |
| template <typename T>
 | |
| using SchemaType = typename SchemaType_<T>::Type;
 | |
| // SchemaType<T> is the type of T's schema, e.g. StructSchema if T is a struct.
 | |
| 
 | |
| namespace _ {  // private
 | |
| extern const RawSchema NULL_SCHEMA;
 | |
| extern const RawSchema NULL_STRUCT_SCHEMA;
 | |
| extern const RawSchema NULL_ENUM_SCHEMA;
 | |
| extern const RawSchema NULL_INTERFACE_SCHEMA;
 | |
| extern const RawSchema NULL_CONST_SCHEMA;
 | |
| // The schema types default to these null (empty) schemas in case of error, especially when
 | |
| // exceptions are disabled.
 | |
| }  // namespace _ (private)
 | |
| 
 | |
| class Schema {
 | |
|   // Convenience wrapper around capnp::schema::Node.
 | |
| 
 | |
| public:
 | |
|   inline Schema(): raw(&_::NULL_SCHEMA.defaultBrand) {}
 | |
| 
 | |
|   template <typename T>
 | |
|   static inline SchemaType<T> from() { return SchemaType<T>::template fromImpl<T>(); }
 | |
|   // Get the Schema for a particular compiled-in type.
 | |
| 
 | |
|   schema::Node::Reader getProto() const;
 | |
|   // Get the underlying Cap'n Proto representation of the schema node.  (Note that this accessor
 | |
|   // has performance comparable to accessors of struct-typed fields on Reader classes.)
 | |
| 
 | |
|   kj::ArrayPtr<const word> asUncheckedMessage() const;
 | |
|   // Get the encoded schema node content as a single message segment.  It is safe to read as an
 | |
|   // unchecked message.
 | |
| 
 | |
|   Schema getDependency(uint64_t id) const KJ_DEPRECATED("Does not handle generics correctly.");
 | |
|   // DEPRECATED: This method cannot correctly account for generic type parameter bindings that
 | |
|   //   may apply to the dependency. Instead of using this method, use a method of the Schema API
 | |
|   //   that corresponds to the exact kind of dependency. For example, to get a field type, use
 | |
|   //   StructSchema::Field::getType().
 | |
|   //
 | |
|   // Gets the Schema for one of this Schema's dependencies.  For example, if this Schema is for a
 | |
|   // struct, you could look up the schema for one of its fields' types.  Throws an exception if this
 | |
|   // schema doesn't actually depend on the given id.
 | |
|   //
 | |
|   // Note that not all type IDs found in the schema node are considered "dependencies" -- only the
 | |
|   // ones that are needed to implement the dynamic API are.  That includes:
 | |
|   // - Field types.
 | |
|   // - Group types.
 | |
|   // - scopeId for group nodes, but NOT otherwise.
 | |
|   // - Method parameter and return types.
 | |
|   //
 | |
|   // The following are NOT considered dependencies:
 | |
|   // - Nested nodes.
 | |
|   // - scopeId for a non-group node.
 | |
|   // - Annotations.
 | |
|   //
 | |
|   // To obtain schemas for those, you would need a SchemaLoader.
 | |
| 
 | |
|   bool isBranded() const;
 | |
|   // Returns true if this schema represents a non-default parameterization of this type.
 | |
| 
 | |
|   Schema getGeneric() const;
 | |
|   // Get the version of this schema with any brands removed.
 | |
| 
 | |
|   class BrandArgumentList;
 | |
|   BrandArgumentList getBrandArgumentsAtScope(uint64_t scopeId) const;
 | |
|   // Gets the values bound to the brand parameters at the given scope.
 | |
| 
 | |
|   StructSchema asStruct() const;
 | |
|   EnumSchema asEnum() const;
 | |
|   InterfaceSchema asInterface() const;
 | |
|   ConstSchema asConst() const;
 | |
|   // Cast the Schema to a specific type.  Throws an exception if the type doesn't match.  Use
 | |
|   // getProto() to determine type, e.g. getProto().isStruct().
 | |
| 
 | |
|   inline bool operator==(const Schema& other) const { return raw == other.raw; }
 | |
|   inline bool operator!=(const Schema& other) const { return raw != other.raw; }
 | |
|   // Determine whether two Schemas are wrapping the exact same underlying data, by identity.  If
 | |
|   // you want to check if two Schemas represent the same type (but possibly different versions of
 | |
|   // it), compare their IDs instead.
 | |
| 
 | |
|   template <typename T>
 | |
|   void requireUsableAs() const;
 | |
|   // Throws an exception if a value with this Schema cannot safely be cast to a native value of
 | |
|   // the given type.  This passes if either:
 | |
|   // - *this == from<T>()
 | |
|   // - This schema was loaded with SchemaLoader, the type ID matches typeId<T>(), and
 | |
|   //   loadCompiledTypeAndDependencies<T>() was called on the SchemaLoader.
 | |
| 
 | |
|   kj::StringPtr getShortDisplayName() const;
 | |
|   // Get the short version of the node's display name.
 | |
| 
 | |
| private:
 | |
|   const _::RawBrandedSchema* raw;
 | |
| 
 | |
|   inline explicit Schema(const _::RawBrandedSchema* raw): raw(raw) {
 | |
|     KJ_IREQUIRE(raw->lazyInitializer == nullptr,
 | |
|         "Must call ensureInitialized() on RawSchema before constructing Schema.");
 | |
|   }
 | |
| 
 | |
|   template <typename T> static inline Schema fromImpl() {
 | |
|     return Schema(&_::rawSchema<T>());
 | |
|   }
 | |
| 
 | |
|   void requireUsableAs(const _::RawSchema* expected) const;
 | |
| 
 | |
|   uint32_t getSchemaOffset(const schema::Value::Reader& value) const;
 | |
| 
 | |
|   Type getBrandBinding(uint64_t scopeId, uint index) const;
 | |
|   // Look up the binding for a brand parameter used by this Schema. Returns `AnyPointer` if the
 | |
|   // parameter is not bound.
 | |
|   //
 | |
|   // TODO(someday): Public interface for iterating over all bindings?
 | |
| 
 | |
|   Schema getDependency(uint64_t id, uint location) const;
 | |
|   // Look up schema for a particular dependency of this schema. `location` is the dependency
 | |
|   // location number as defined in _::RawBrandedSchema.
 | |
| 
 | |
|   Type interpretType(schema::Type::Reader proto, uint location) const;
 | |
|   // Interpret a schema::Type in the given location within the schema, compiling it into a
 | |
|   // Type object.
 | |
| 
 | |
|   friend class StructSchema;
 | |
|   friend class EnumSchema;
 | |
|   friend class InterfaceSchema;
 | |
|   friend class ConstSchema;
 | |
|   friend class ListSchema;
 | |
|   friend class SchemaLoader;
 | |
|   friend class Type;
 | |
|   friend kj::StringTree _::structString(
 | |
|       _::StructReader reader, const _::RawBrandedSchema& schema);
 | |
|   friend kj::String _::enumString(uint16_t value, const _::RawBrandedSchema& schema);
 | |
| };
 | |
| 
 | |
| kj::StringPtr KJ_STRINGIFY(const Schema& schema);
 | |
| 
 | |
| class Schema::BrandArgumentList {
 | |
|   // A list of generic parameter bindings for parameters of some particular type. Note that since
 | |
|   // parameters on an outer type apply to all inner types as well, a deeply-nested type can have
 | |
|   // multiple BrandArgumentLists that apply to it.
 | |
|   //
 | |
|   // A BrandArgumentList only represents the arguments that the client of the type specified. Since
 | |
|   // new parameters can be added over time, this list may not cover all defined parameters for the
 | |
|   // type. Missing parameters should be treated as AnyPointer. This class's implementation of
 | |
|   // operator[] already does this for you; out-of-bounds access will safely return AnyPointer.
 | |
| 
 | |
| public:
 | |
|   inline BrandArgumentList(): scopeId(0), size_(0), bindings(nullptr) {}
 | |
| 
 | |
|   inline uint size() const { return size_; }
 | |
|   Type operator[](uint index) const;
 | |
| 
 | |
|   typedef _::IndexingIterator<const BrandArgumentList, Type> Iterator;
 | |
|   inline Iterator begin() const { return Iterator(this, 0); }
 | |
|   inline Iterator end() const { return Iterator(this, size()); }
 | |
| 
 | |
| private:
 | |
|   uint64_t scopeId;
 | |
|   uint size_;
 | |
|   bool isUnbound;
 | |
|   const _::RawBrandedSchema::Binding* bindings;
 | |
| 
 | |
|   inline BrandArgumentList(uint64_t scopeId, bool isUnbound)
 | |
|       : scopeId(scopeId), size_(0), isUnbound(isUnbound), bindings(nullptr) {}
 | |
|   inline BrandArgumentList(uint64_t scopeId, uint size,
 | |
|                            const _::RawBrandedSchema::Binding* bindings)
 | |
|       : scopeId(scopeId), size_(size), isUnbound(false), bindings(bindings) {}
 | |
| 
 | |
|   friend class Schema;
 | |
| };
 | |
| 
 | |
| // -------------------------------------------------------------------
 | |
| 
 | |
| class StructSchema: public Schema {
 | |
| public:
 | |
|   inline StructSchema(): Schema(&_::NULL_STRUCT_SCHEMA.defaultBrand) {}
 | |
| 
 | |
|   class Field;
 | |
|   class FieldList;
 | |
|   class FieldSubset;
 | |
| 
 | |
|   FieldList getFields() const;
 | |
|   // List top-level fields of this struct.  This list will contain top-level groups (including
 | |
|   // named unions) but not the members of those groups.  The list does, however, contain the
 | |
|   // members of the unnamed union, if there is one.
 | |
| 
 | |
|   FieldSubset getUnionFields() const;
 | |
|   // If the field contains an unnamed union, get a list of fields in the union, ordered by
 | |
|   // ordinal.  Since discriminant values are assigned sequentially by ordinal, you may index this
 | |
|   // list by discriminant value.
 | |
| 
 | |
|   FieldSubset getNonUnionFields() const;
 | |
|   // Get the fields of this struct which are not in an unnamed union, ordered by ordinal.
 | |
| 
 | |
|   kj::Maybe<Field> findFieldByName(kj::StringPtr name) const;
 | |
|   // Find the field with the given name, or return null if there is no such field.  If the struct
 | |
|   // contains an unnamed union, then this will find fields of that union in addition to fields
 | |
|   // of the outer struct, since they exist in the same namespace.  It will not, however, find
 | |
|   // members of groups (including named unions) -- you must first look up the group itself,
 | |
|   // then dig into its type.
 | |
| 
 | |
|   Field getFieldByName(kj::StringPtr name) const;
 | |
|   // Like findFieldByName() but throws an exception on failure.
 | |
| 
 | |
|   kj::Maybe<Field> getFieldByDiscriminant(uint16_t discriminant) const;
 | |
|   // Finds the field whose `discriminantValue` is equal to the given value, or returns null if
 | |
|   // there is no such field.  (If the schema does not represent a union or a struct containing
 | |
|   // an unnamed union, then this always returns null.)
 | |
| 
 | |
| private:
 | |
|   StructSchema(Schema base): Schema(base) {}
 | |
|   template <typename T> static inline StructSchema fromImpl() {
 | |
|     return StructSchema(Schema(&_::rawBrandedSchema<T>()));
 | |
|   }
 | |
|   friend class Schema;
 | |
|   friend class Type;
 | |
| };
 | |
| 
 | |
| class StructSchema::Field {
 | |
| public:
 | |
|   Field() = default;
 | |
| 
 | |
|   inline schema::Field::Reader getProto() const { return proto; }
 | |
|   inline StructSchema getContainingStruct() const { return parent; }
 | |
| 
 | |
|   inline uint getIndex() const { return index; }
 | |
|   // Get the index of this field within the containing struct or union.
 | |
| 
 | |
|   Type getType() const;
 | |
|   // Get the type of this field. Note that this is preferred over getProto().getType() as this
 | |
|   // method will apply generics.
 | |
| 
 | |
|   uint32_t getDefaultValueSchemaOffset() const;
 | |
|   // For struct, list, and object fields, returns the offset, in words, within the first segment of
 | |
|   // the struct's schema, where this field's default value pointer is located.  The schema is
 | |
|   // always stored as a single-segment unchecked message, which in turn means that the default
 | |
|   // value pointer itself can be treated as the root of an unchecked message -- if you know where
 | |
|   // to find it, which is what this method helps you with.
 | |
|   //
 | |
|   // For blobs, returns the offset of the beginning of the blob's content within the first segment
 | |
|   // of the struct's schema.
 | |
|   //
 | |
|   // This is primarily useful for code generators.  The C++ code generator, for example, embeds
 | |
|   // the entire schema as a raw word array within the generated code.  Of course, to implement
 | |
|   // field accessors, it needs access to those fields' default values.  Embedding separate copies
 | |
|   // of those default values would be redundant since they are already included in the schema, but
 | |
|   // seeking through the schema at runtime to find the default values would be ugly.  Instead,
 | |
|   // the code generator can use getDefaultValueSchemaOffset() to find the offset of the default
 | |
|   // value within the schema, and can simply apply that offset at runtime.
 | |
|   //
 | |
|   // If the above does not make sense, you probably don't need this method.
 | |
| 
 | |
|   inline bool operator==(const Field& other) const;
 | |
|   inline bool operator!=(const Field& other) const { return !(*this == other); }
 | |
| 
 | |
| private:
 | |
|   StructSchema parent;
 | |
|   uint index;
 | |
|   schema::Field::Reader proto;
 | |
| 
 | |
|   inline Field(StructSchema parent, uint index, schema::Field::Reader proto)
 | |
|       : parent(parent), index(index), proto(proto) {}
 | |
| 
 | |
|   friend class StructSchema;
 | |
| };
 | |
| 
 | |
| kj::StringPtr KJ_STRINGIFY(const StructSchema::Field& field);
 | |
| 
 | |
| class StructSchema::FieldList {
 | |
| public:
 | |
|   FieldList() = default;  // empty list
 | |
| 
 | |
|   inline uint size() const { return list.size(); }
 | |
|   inline Field operator[](uint index) const { return Field(parent, index, list[index]); }
 | |
| 
 | |
|   typedef _::IndexingIterator<const FieldList, Field> Iterator;
 | |
|   inline Iterator begin() const { return Iterator(this, 0); }
 | |
|   inline Iterator end() const { return Iterator(this, size()); }
 | |
| 
 | |
| private:
 | |
|   StructSchema parent;
 | |
|   List<schema::Field>::Reader list;
 | |
| 
 | |
|   inline FieldList(StructSchema parent, List<schema::Field>::Reader list)
 | |
|       : parent(parent), list(list) {}
 | |
| 
 | |
|   friend class StructSchema;
 | |
| };
 | |
| 
 | |
| class StructSchema::FieldSubset {
 | |
| public:
 | |
|   FieldSubset() = default;  // empty list
 | |
| 
 | |
|   inline uint size() const { return size_; }
 | |
|   inline Field operator[](uint index) const {
 | |
|     return Field(parent, indices[index], list[indices[index]]);
 | |
|   }
 | |
| 
 | |
|   typedef _::IndexingIterator<const FieldSubset, Field> Iterator;
 | |
|   inline Iterator begin() const { return Iterator(this, 0); }
 | |
|   inline Iterator end() const { return Iterator(this, size()); }
 | |
| 
 | |
| private:
 | |
|   StructSchema parent;
 | |
|   List<schema::Field>::Reader list;
 | |
|   const uint16_t* indices;
 | |
|   uint size_;
 | |
| 
 | |
|   inline FieldSubset(StructSchema parent, List<schema::Field>::Reader list,
 | |
|                      const uint16_t* indices, uint size)
 | |
|       : parent(parent), list(list), indices(indices), size_(size) {}
 | |
| 
 | |
|   friend class StructSchema;
 | |
| };
 | |
| 
 | |
| // -------------------------------------------------------------------
 | |
| 
 | |
| class EnumSchema: public Schema {
 | |
| public:
 | |
|   inline EnumSchema(): Schema(&_::NULL_ENUM_SCHEMA.defaultBrand) {}
 | |
| 
 | |
|   class Enumerant;
 | |
|   class EnumerantList;
 | |
| 
 | |
|   EnumerantList getEnumerants() const;
 | |
| 
 | |
|   kj::Maybe<Enumerant> findEnumerantByName(kj::StringPtr name) const;
 | |
| 
 | |
|   Enumerant getEnumerantByName(kj::StringPtr name) const;
 | |
|   // Like findEnumerantByName() but throws an exception on failure.
 | |
| 
 | |
| private:
 | |
|   EnumSchema(Schema base): Schema(base) {}
 | |
|   template <typename T> static inline EnumSchema fromImpl() {
 | |
|     return EnumSchema(Schema(&_::rawBrandedSchema<T>()));
 | |
|   }
 | |
|   friend class Schema;
 | |
|   friend class Type;
 | |
| };
 | |
| 
 | |
| class EnumSchema::Enumerant {
 | |
| public:
 | |
|   Enumerant() = default;
 | |
| 
 | |
|   inline schema::Enumerant::Reader getProto() const { return proto; }
 | |
|   inline EnumSchema getContainingEnum() const { return parent; }
 | |
| 
 | |
|   inline uint16_t getOrdinal() const { return ordinal; }
 | |
|   inline uint getIndex() const { return ordinal; }
 | |
| 
 | |
|   inline bool operator==(const Enumerant& other) const;
 | |
|   inline bool operator!=(const Enumerant& other) const { return !(*this == other); }
 | |
| 
 | |
| private:
 | |
|   EnumSchema parent;
 | |
|   uint16_t ordinal;
 | |
|   schema::Enumerant::Reader proto;
 | |
| 
 | |
|   inline Enumerant(EnumSchema parent, uint16_t ordinal, schema::Enumerant::Reader proto)
 | |
|       : parent(parent), ordinal(ordinal), proto(proto) {}
 | |
| 
 | |
|   friend class EnumSchema;
 | |
| };
 | |
| 
 | |
| class EnumSchema::EnumerantList {
 | |
| public:
 | |
|   EnumerantList() = default;  // empty list
 | |
| 
 | |
|   inline uint size() const { return list.size(); }
 | |
|   inline Enumerant operator[](uint index) const { return Enumerant(parent, index, list[index]); }
 | |
| 
 | |
|   typedef _::IndexingIterator<const EnumerantList, Enumerant> Iterator;
 | |
|   inline Iterator begin() const { return Iterator(this, 0); }
 | |
|   inline Iterator end() const { return Iterator(this, size()); }
 | |
| 
 | |
| private:
 | |
|   EnumSchema parent;
 | |
|   List<schema::Enumerant>::Reader list;
 | |
| 
 | |
|   inline EnumerantList(EnumSchema parent, List<schema::Enumerant>::Reader list)
 | |
|       : parent(parent), list(list) {}
 | |
| 
 | |
|   friend class EnumSchema;
 | |
| };
 | |
| 
 | |
| // -------------------------------------------------------------------
 | |
| 
 | |
| class InterfaceSchema: public Schema {
 | |
| public:
 | |
|   inline InterfaceSchema(): Schema(&_::NULL_INTERFACE_SCHEMA.defaultBrand) {}
 | |
| 
 | |
|   class Method;
 | |
|   class MethodList;
 | |
| 
 | |
|   MethodList getMethods() const;
 | |
| 
 | |
|   kj::Maybe<Method> findMethodByName(kj::StringPtr name) const;
 | |
| 
 | |
|   Method getMethodByName(kj::StringPtr name) const;
 | |
|   // Like findMethodByName() but throws an exception on failure.
 | |
| 
 | |
|   class SuperclassList;
 | |
| 
 | |
|   SuperclassList getSuperclasses() const;
 | |
|   // Get the immediate superclasses of this type, after applying generics.
 | |
| 
 | |
|   bool extends(InterfaceSchema other) const;
 | |
|   // Returns true if `other` is a superclass of this interface (including if `other == *this`).
 | |
| 
 | |
|   kj::Maybe<InterfaceSchema> findSuperclass(uint64_t typeId) const;
 | |
|   // Find the superclass of this interface with the given type ID.  Returns null if the interface
 | |
|   // extends no such type.
 | |
| 
 | |
| private:
 | |
|   InterfaceSchema(Schema base): Schema(base) {}
 | |
|   template <typename T> static inline InterfaceSchema fromImpl() {
 | |
|     return InterfaceSchema(Schema(&_::rawBrandedSchema<T>()));
 | |
|   }
 | |
|   friend class Schema;
 | |
|   friend class Type;
 | |
| 
 | |
|   kj::Maybe<Method> findMethodByName(kj::StringPtr name, uint& counter) const;
 | |
|   bool extends(InterfaceSchema other, uint& counter) const;
 | |
|   kj::Maybe<InterfaceSchema> findSuperclass(uint64_t typeId, uint& counter) const;
 | |
|   // We protect against malicious schemas with large or cyclic hierarchies by cutting off the
 | |
|   // search when the counter reaches a threshold.
 | |
| };
 | |
| 
 | |
| class InterfaceSchema::Method {
 | |
| public:
 | |
|   Method() = default;
 | |
| 
 | |
|   inline schema::Method::Reader getProto() const { return proto; }
 | |
|   inline InterfaceSchema getContainingInterface() const { return parent; }
 | |
| 
 | |
|   inline uint16_t getOrdinal() const { return ordinal; }
 | |
|   inline uint getIndex() const { return ordinal; }
 | |
| 
 | |
|   StructSchema getParamType() const;
 | |
|   StructSchema getResultType() const;
 | |
|   // Get the parameter and result types, including substituting generic parameters.
 | |
| 
 | |
|   inline bool operator==(const Method& other) const;
 | |
|   inline bool operator!=(const Method& other) const { return !(*this == other); }
 | |
| 
 | |
| private:
 | |
|   InterfaceSchema parent;
 | |
|   uint16_t ordinal;
 | |
|   schema::Method::Reader proto;
 | |
| 
 | |
|   inline Method(InterfaceSchema parent, uint16_t ordinal,
 | |
|                 schema::Method::Reader proto)
 | |
|       : parent(parent), ordinal(ordinal), proto(proto) {}
 | |
| 
 | |
|   friend class InterfaceSchema;
 | |
| };
 | |
| 
 | |
| class InterfaceSchema::MethodList {
 | |
| public:
 | |
|   MethodList() = default;  // empty list
 | |
| 
 | |
|   inline uint size() const { return list.size(); }
 | |
|   inline Method operator[](uint index) const { return Method(parent, index, list[index]); }
 | |
| 
 | |
|   typedef _::IndexingIterator<const MethodList, Method> Iterator;
 | |
|   inline Iterator begin() const { return Iterator(this, 0); }
 | |
|   inline Iterator end() const { return Iterator(this, size()); }
 | |
| 
 | |
| private:
 | |
|   InterfaceSchema parent;
 | |
|   List<schema::Method>::Reader list;
 | |
| 
 | |
|   inline MethodList(InterfaceSchema parent, List<schema::Method>::Reader list)
 | |
|       : parent(parent), list(list) {}
 | |
| 
 | |
|   friend class InterfaceSchema;
 | |
| };
 | |
| 
 | |
| class InterfaceSchema::SuperclassList {
 | |
| public:
 | |
|   SuperclassList() = default;  // empty list
 | |
| 
 | |
|   inline uint size() const { return list.size(); }
 | |
|   InterfaceSchema operator[](uint index) const;
 | |
| 
 | |
|   typedef _::IndexingIterator<const SuperclassList, InterfaceSchema> Iterator;
 | |
|   inline Iterator begin() const { return Iterator(this, 0); }
 | |
|   inline Iterator end() const { return Iterator(this, size()); }
 | |
| 
 | |
| private:
 | |
|   InterfaceSchema parent;
 | |
|   List<schema::Superclass>::Reader list;
 | |
| 
 | |
|   inline SuperclassList(InterfaceSchema parent, List<schema::Superclass>::Reader list)
 | |
|       : parent(parent), list(list) {}
 | |
| 
 | |
|   friend class InterfaceSchema;
 | |
| };
 | |
| 
 | |
| // -------------------------------------------------------------------
 | |
| 
 | |
| class ConstSchema: public Schema {
 | |
|   // Represents a constant declaration.
 | |
|   //
 | |
|   // `ConstSchema` can be implicitly cast to DynamicValue to read its value.
 | |
| 
 | |
| public:
 | |
|   inline ConstSchema(): Schema(&_::NULL_CONST_SCHEMA.defaultBrand) {}
 | |
| 
 | |
|   template <typename T>
 | |
|   ReaderFor<T> as() const;
 | |
|   // Read the constant's value.  This is a convenience method equivalent to casting the ConstSchema
 | |
|   // to a DynamicValue and then calling its `as<T>()` method.  For dependency reasons, this method
 | |
|   // is defined in <capnp/dynamic.h>, which you must #include explicitly.
 | |
| 
 | |
|   uint32_t getValueSchemaOffset() const;
 | |
|   // Much like StructSchema::Field::getDefaultValueSchemaOffset(), if the constant has pointer
 | |
|   // type, this gets the offset from the beginning of the constant's schema node to a pointer
 | |
|   // representing the constant value.
 | |
| 
 | |
|   Type getType() const;
 | |
| 
 | |
| private:
 | |
|   ConstSchema(Schema base): Schema(base) {}
 | |
|   friend class Schema;
 | |
| };
 | |
| 
 | |
| // -------------------------------------------------------------------
 | |
| 
 | |
| class Type {
 | |
| public:
 | |
|   struct BrandParameter {
 | |
|     uint64_t scopeId;
 | |
|     uint index;
 | |
|   };
 | |
|   struct ImplicitParameter {
 | |
|     uint index;
 | |
|   };
 | |
| 
 | |
|   inline Type();
 | |
|   inline Type(schema::Type::Which primitive);
 | |
|   inline Type(StructSchema schema);
 | |
|   inline Type(EnumSchema schema);
 | |
|   inline Type(InterfaceSchema schema);
 | |
|   inline Type(ListSchema schema);
 | |
|   inline Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind);
 | |
|   inline Type(BrandParameter param);
 | |
|   inline Type(ImplicitParameter param);
 | |
| 
 | |
|   template <typename T>
 | |
|   inline static Type from();
 | |
| 
 | |
|   inline schema::Type::Which which() const;
 | |
| 
 | |
|   StructSchema asStruct() const;
 | |
|   EnumSchema asEnum() const;
 | |
|   InterfaceSchema asInterface() const;
 | |
|   ListSchema asList() const;
 | |
|   // Each of these methods may only be called if which() returns the corresponding type.
 | |
| 
 | |
|   kj::Maybe<BrandParameter> getBrandParameter() const;
 | |
|   // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular
 | |
|   // AnyPointer and not a parameter.
 | |
| 
 | |
|   kj::Maybe<ImplicitParameter> getImplicitParameter() const;
 | |
|   // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular
 | |
|   // AnyPointer and not a parameter. "Implicit parameters" refer to type parameters on methods.
 | |
| 
 | |
|   inline schema::Type::AnyPointer::Unconstrained::Which whichAnyPointerKind() const;
 | |
|   // Only callable if which() returns ANY_POINTER.
 | |
| 
 | |
|   inline bool isVoid() const;
 | |
|   inline bool isBool() const;
 | |
|   inline bool isInt8() const;
 | |
|   inline bool isInt16() const;
 | |
|   inline bool isInt32() const;
 | |
|   inline bool isInt64() const;
 | |
|   inline bool isUInt8() const;
 | |
|   inline bool isUInt16() const;
 | |
|   inline bool isUInt32() const;
 | |
|   inline bool isUInt64() const;
 | |
|   inline bool isFloat32() const;
 | |
|   inline bool isFloat64() const;
 | |
|   inline bool isText() const;
 | |
|   inline bool isData() const;
 | |
|   inline bool isList() const;
 | |
|   inline bool isEnum() const;
 | |
|   inline bool isStruct() const;
 | |
|   inline bool isInterface() const;
 | |
|   inline bool isAnyPointer() const;
 | |
| 
 | |
|   bool operator==(const Type& other) const;
 | |
|   inline bool operator!=(const Type& other) const { return !(*this == other); }
 | |
| 
 | |
|   size_t hashCode() const;
 | |
| 
 | |
|   inline Type wrapInList(uint depth = 1) const;
 | |
|   // Return the Type formed by wrapping this type in List() `depth` times.
 | |
| 
 | |
|   inline Type(schema::Type::Which derived, const _::RawBrandedSchema* schema);
 | |
|   // For internal use.
 | |
| 
 | |
| private:
 | |
|   schema::Type::Which baseType;  // type not including applications of List()
 | |
|   uint8_t listDepth;             // 0 for T, 1 for List(T), 2 for List(List(T)), ...
 | |
| 
 | |
|   bool isImplicitParam;
 | |
|   // If true, this refers to an implicit method parameter. baseType must be ANY_POINTER, scopeId
 | |
|   // must be zero, and paramIndex indicates the parameter index.
 | |
| 
 | |
|   union {
 | |
|     uint16_t paramIndex;
 | |
|     // If baseType is ANY_POINTER but this Type actually refers to a type parameter, this is the
 | |
|     // index of the parameter among the parameters at its scope, and `scopeId` below is the type ID
 | |
|     // of the scope where the parameter was defined.
 | |
| 
 | |
|     schema::Type::AnyPointer::Unconstrained::Which anyPointerKind;
 | |
|     // If scopeId is zero and isImplicitParam is false.
 | |
|   };
 | |
| 
 | |
|   union {
 | |
|     const _::RawBrandedSchema* schema;  // if type is struct, enum, interface...
 | |
|     uint64_t scopeId;  // if type is AnyPointer but it's actually a type parameter...
 | |
|   };
 | |
| 
 | |
|   Type(schema::Type::Which baseType, uint8_t listDepth, const _::RawBrandedSchema* schema)
 | |
|       : baseType(baseType), listDepth(listDepth), schema(schema) {
 | |
|     KJ_IREQUIRE(baseType != schema::Type::ANY_POINTER);
 | |
|   }
 | |
| 
 | |
|   void requireUsableAs(Type expected) const;
 | |
| 
 | |
|   friend class ListSchema;  // only for requireUsableAs()
 | |
| };
 | |
| 
 | |
| // -------------------------------------------------------------------
 | |
| 
 | |
| class ListSchema {
 | |
|   // ListSchema is a little different because list types are not described by schema nodes.  So,
 | |
|   // ListSchema doesn't subclass Schema.
 | |
| 
 | |
| public:
 | |
|   ListSchema() = default;
 | |
| 
 | |
|   static ListSchema of(schema::Type::Which primitiveType);
 | |
|   static ListSchema of(StructSchema elementType);
 | |
|   static ListSchema of(EnumSchema elementType);
 | |
|   static ListSchema of(InterfaceSchema elementType);
 | |
|   static ListSchema of(ListSchema elementType);
 | |
|   static ListSchema of(Type elementType);
 | |
|   // Construct the schema for a list of the given type.
 | |
| 
 | |
|   static ListSchema of(schema::Type::Reader elementType, Schema context)
 | |
|       KJ_DEPRECATED("Does not handle generics correctly.");
 | |
|   // DEPRECATED: This method cannot correctly account for generic type parameter bindings that
 | |
|   //   may apply to the input type. Instead of using this method, use a method of the Schema API
 | |
|   //   that corresponds to the exact kind of dependency. For example, to get a field type, use
 | |
|   //   StructSchema::Field::getType().
 | |
|   //
 | |
|   // Construct from an element type schema.  Requires a context which can handle getDependency()
 | |
|   // requests for any type ID found in the schema.
 | |
| 
 | |
|   Type getElementType() const;
 | |
| 
 | |
|   inline schema::Type::Which whichElementType() const;
 | |
|   // Get the element type's "which()".  ListSchema does not actually store a schema::Type::Reader
 | |
|   // describing the element type, but if it did, this would be equivalent to calling
 | |
|   // .getBody().which() on that type.
 | |
| 
 | |
|   StructSchema getStructElementType() const;
 | |
|   EnumSchema getEnumElementType() const;
 | |
|   InterfaceSchema getInterfaceElementType() const;
 | |
|   ListSchema getListElementType() const;
 | |
|   // Get the schema for complex element types.  Each of these throws an exception if the element
 | |
|   // type is not of the requested kind.
 | |
| 
 | |
|   inline bool operator==(const ListSchema& other) const { return elementType == other.elementType; }
 | |
|   inline bool operator!=(const ListSchema& other) const { return elementType != other.elementType; }
 | |
| 
 | |
|   template <typename T>
 | |
|   void requireUsableAs() const;
 | |
| 
 | |
| private:
 | |
|   Type elementType;
 | |
| 
 | |
|   inline explicit ListSchema(Type elementType): elementType(elementType) {}
 | |
| 
 | |
|   template <typename T>
 | |
|   struct FromImpl;
 | |
|   template <typename T> static inline ListSchema fromImpl() {
 | |
|     return FromImpl<T>::get();
 | |
|   }
 | |
| 
 | |
|   void requireUsableAs(ListSchema expected) const;
 | |
| 
 | |
|   friend class Schema;
 | |
| };
 | |
| 
 | |
| // =======================================================================================
 | |
| // inline implementation
 | |
| 
 | |
| template <> inline schema::Type::Which Schema::from<Void>() { return schema::Type::VOID; }
 | |
| template <> inline schema::Type::Which Schema::from<bool>() { return schema::Type::BOOL; }
 | |
| template <> inline schema::Type::Which Schema::from<int8_t>() { return schema::Type::INT8; }
 | |
| template <> inline schema::Type::Which Schema::from<int16_t>() { return schema::Type::INT16; }
 | |
| template <> inline schema::Type::Which Schema::from<int32_t>() { return schema::Type::INT32; }
 | |
| template <> inline schema::Type::Which Schema::from<int64_t>() { return schema::Type::INT64; }
 | |
| template <> inline schema::Type::Which Schema::from<uint8_t>() { return schema::Type::UINT8; }
 | |
| template <> inline schema::Type::Which Schema::from<uint16_t>() { return schema::Type::UINT16; }
 | |
| template <> inline schema::Type::Which Schema::from<uint32_t>() { return schema::Type::UINT32; }
 | |
| template <> inline schema::Type::Which Schema::from<uint64_t>() { return schema::Type::UINT64; }
 | |
| template <> inline schema::Type::Which Schema::from<float>() { return schema::Type::FLOAT32; }
 | |
| template <> inline schema::Type::Which Schema::from<double>() { return schema::Type::FLOAT64; }
 | |
| template <> inline schema::Type::Which Schema::from<Text>() { return schema::Type::TEXT; }
 | |
| template <> inline schema::Type::Which Schema::from<Data>() { return schema::Type::DATA; }
 | |
| 
 | |
| inline Schema Schema::getDependency(uint64_t id) const {
 | |
|   return getDependency(id, 0);
 | |
| }
 | |
| 
 | |
| inline bool Schema::isBranded() const {
 | |
|   return raw != &raw->generic->defaultBrand;
 | |
| }
 | |
| 
 | |
| inline Schema Schema::getGeneric() const {
 | |
|   return Schema(&raw->generic->defaultBrand);
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| inline void Schema::requireUsableAs() const {
 | |
|   requireUsableAs(&_::rawSchema<T>());
 | |
| }
 | |
| 
 | |
| inline bool StructSchema::Field::operator==(const Field& other) const {
 | |
|   return parent == other.parent && index == other.index;
 | |
| }
 | |
| inline bool EnumSchema::Enumerant::operator==(const Enumerant& other) const {
 | |
|   return parent == other.parent && ordinal == other.ordinal;
 | |
| }
 | |
| inline bool InterfaceSchema::Method::operator==(const Method& other) const {
 | |
|   return parent == other.parent && ordinal == other.ordinal;
 | |
| }
 | |
| 
 | |
| inline ListSchema ListSchema::of(StructSchema elementType) {
 | |
|   return ListSchema(Type(elementType));
 | |
| }
 | |
| inline ListSchema ListSchema::of(EnumSchema elementType) {
 | |
|   return ListSchema(Type(elementType));
 | |
| }
 | |
| inline ListSchema ListSchema::of(InterfaceSchema elementType) {
 | |
|   return ListSchema(Type(elementType));
 | |
| }
 | |
| inline ListSchema ListSchema::of(ListSchema elementType) {
 | |
|   return ListSchema(Type(elementType));
 | |
| }
 | |
| inline ListSchema ListSchema::of(Type elementType) {
 | |
|   return ListSchema(elementType);
 | |
| }
 | |
| 
 | |
| inline Type ListSchema::getElementType() const {
 | |
|   return elementType;
 | |
| }
 | |
| 
 | |
| inline schema::Type::Which ListSchema::whichElementType() const {
 | |
|   return elementType.which();
 | |
| }
 | |
| 
 | |
| inline StructSchema ListSchema::getStructElementType() const {
 | |
|   return elementType.asStruct();
 | |
| }
 | |
| 
 | |
| inline EnumSchema ListSchema::getEnumElementType() const {
 | |
|   return elementType.asEnum();
 | |
| }
 | |
| 
 | |
| inline InterfaceSchema ListSchema::getInterfaceElementType() const {
 | |
|   return elementType.asInterface();
 | |
| }
 | |
| 
 | |
| inline ListSchema ListSchema::getListElementType() const {
 | |
|   return elementType.asList();
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| inline void ListSchema::requireUsableAs() const {
 | |
|   static_assert(kind<T>() == Kind::LIST,
 | |
|                 "ListSchema::requireUsableAs<T>() requires T is a list type.");
 | |
|   requireUsableAs(Schema::from<T>());
 | |
| }
 | |
| 
 | |
| inline void ListSchema::requireUsableAs(ListSchema expected) const {
 | |
|   elementType.requireUsableAs(expected.elementType);
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| struct ListSchema::FromImpl<List<T>> {
 | |
|   static inline ListSchema get() { return of(Schema::from<T>()); }
 | |
| };
 | |
| 
 | |
| inline Type::Type(): baseType(schema::Type::VOID), listDepth(0), schema(nullptr) {}
 | |
| inline Type::Type(schema::Type::Which primitive)
 | |
|     : baseType(primitive), listDepth(0), isImplicitParam(false) {
 | |
|   KJ_IREQUIRE(primitive != schema::Type::STRUCT &&
 | |
|               primitive != schema::Type::ENUM &&
 | |
|               primitive != schema::Type::INTERFACE &&
 | |
|               primitive != schema::Type::LIST);
 | |
|   if (primitive == schema::Type::ANY_POINTER) {
 | |
|     scopeId = 0;
 | |
|     anyPointerKind = schema::Type::AnyPointer::Unconstrained::ANY_KIND;
 | |
|   } else {
 | |
|     schema = nullptr;
 | |
|   }
 | |
| }
 | |
| inline Type::Type(schema::Type::Which derived, const _::RawBrandedSchema* schema)
 | |
|     : baseType(derived), listDepth(0), isImplicitParam(false), schema(schema) {
 | |
|   KJ_IREQUIRE(derived == schema::Type::STRUCT ||
 | |
|               derived == schema::Type::ENUM ||
 | |
|               derived == schema::Type::INTERFACE);
 | |
| }
 | |
| 
 | |
| inline Type::Type(StructSchema schema)
 | |
|     : baseType(schema::Type::STRUCT), listDepth(0), schema(schema.raw) {}
 | |
| inline Type::Type(EnumSchema schema)
 | |
|     : baseType(schema::Type::ENUM), listDepth(0), schema(schema.raw) {}
 | |
| inline Type::Type(InterfaceSchema schema)
 | |
|     : baseType(schema::Type::INTERFACE), listDepth(0), schema(schema.raw) {}
 | |
| inline Type::Type(ListSchema schema)
 | |
|     : Type(schema.getElementType()) { ++listDepth; }
 | |
| inline Type::Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind)
 | |
|     : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false),
 | |
|       anyPointerKind(anyPointerKind), scopeId(0) {}
 | |
| inline Type::Type(BrandParameter param)
 | |
|     : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false),
 | |
|       paramIndex(param.index), scopeId(param.scopeId) {}
 | |
| inline Type::Type(ImplicitParameter param)
 | |
|     : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(true),
 | |
|       paramIndex(param.index), scopeId(0) {}
 | |
| 
 | |
| inline schema::Type::Which Type::which() const {
 | |
|   return listDepth > 0 ? schema::Type::LIST : baseType;
 | |
| }
 | |
| 
 | |
| inline schema::Type::AnyPointer::Unconstrained::Which Type::whichAnyPointerKind() const {
 | |
|   KJ_IREQUIRE(baseType == schema::Type::ANY_POINTER);
 | |
|   return !isImplicitParam && scopeId == 0 ? anyPointerKind
 | |
|       : schema::Type::AnyPointer::Unconstrained::ANY_KIND;
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| inline Type Type::from() { return Type(Schema::from<T>()); }
 | |
| 
 | |
| inline bool Type::isVoid   () const { return baseType == schema::Type::VOID     && listDepth == 0; }
 | |
| inline bool Type::isBool   () const { return baseType == schema::Type::BOOL     && listDepth == 0; }
 | |
| inline bool Type::isInt8   () const { return baseType == schema::Type::INT8     && listDepth == 0; }
 | |
| inline bool Type::isInt16  () const { return baseType == schema::Type::INT16    && listDepth == 0; }
 | |
| inline bool Type::isInt32  () const { return baseType == schema::Type::INT32    && listDepth == 0; }
 | |
| inline bool Type::isInt64  () const { return baseType == schema::Type::INT64    && listDepth == 0; }
 | |
| inline bool Type::isUInt8  () const { return baseType == schema::Type::UINT8    && listDepth == 0; }
 | |
| inline bool Type::isUInt16 () const { return baseType == schema::Type::UINT16   && listDepth == 0; }
 | |
| inline bool Type::isUInt32 () const { return baseType == schema::Type::UINT32   && listDepth == 0; }
 | |
| inline bool Type::isUInt64 () const { return baseType == schema::Type::UINT64   && listDepth == 0; }
 | |
| inline bool Type::isFloat32() const { return baseType == schema::Type::FLOAT32  && listDepth == 0; }
 | |
| inline bool Type::isFloat64() const { return baseType == schema::Type::FLOAT64  && listDepth == 0; }
 | |
| inline bool Type::isText   () const { return baseType == schema::Type::TEXT     && listDepth == 0; }
 | |
| inline bool Type::isData   () const { return baseType == schema::Type::DATA     && listDepth == 0; }
 | |
| inline bool Type::isList   () const { return listDepth > 0; }
 | |
| inline bool Type::isEnum   () const { return baseType == schema::Type::ENUM     && listDepth == 0; }
 | |
| inline bool Type::isStruct () const { return baseType == schema::Type::STRUCT   && listDepth == 0; }
 | |
| inline bool Type::isInterface() const {
 | |
|   return baseType == schema::Type::INTERFACE && listDepth == 0;
 | |
| }
 | |
| inline bool Type::isAnyPointer() const {
 | |
|   return baseType == schema::Type::ANY_POINTER && listDepth == 0;
 | |
| }
 | |
| 
 | |
| inline Type Type::wrapInList(uint depth) const {
 | |
|   Type result = *this;
 | |
|   result.listDepth += depth;
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| }  // namespace capnp
 | |
| 
 | |
| #endif  // CAPNP_SCHEMA_H_
 | |
| 
 |