| 1 | // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors | 
|---|
| 2 | // Licensed under the MIT License: | 
|---|
| 3 | // | 
|---|
| 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy | 
|---|
| 5 | // of this software and associated documentation files (the "Software"), to deal | 
|---|
| 6 | // in the Software without restriction, including without limitation the rights | 
|---|
| 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | 
|---|
| 8 | // copies of the Software, and to permit persons to whom the Software is | 
|---|
| 9 | // furnished to do so, subject to the following conditions: | 
|---|
| 10 | // | 
|---|
| 11 | // The above copyright notice and this permission notice shall be included in | 
|---|
| 12 | // all copies or substantial portions of the Software. | 
|---|
| 13 | // | 
|---|
| 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
|---|
| 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | 
|---|
| 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | 
|---|
| 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | 
|---|
| 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 
|---|
| 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | 
|---|
| 20 | // THE SOFTWARE. | 
|---|
| 21 |  | 
|---|
| 22 | #pragma once | 
|---|
| 23 |  | 
|---|
| 24 | #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) | 
|---|
| 25 | #pragma GCC system_header | 
|---|
| 26 | #endif | 
|---|
| 27 |  | 
|---|
| 28 | #if CAPNP_LITE | 
|---|
| 29 | #error "Reflection APIs, including this header, are not available in lite mode." | 
|---|
| 30 | #endif | 
|---|
| 31 |  | 
|---|
| 32 | #include <capnp/schema.capnp.h> | 
|---|
| 33 | #include <kj/hash.h> | 
|---|
| 34 | #include <kj/windows-sanity.h>  // work-around macro conflict with `VOID` | 
|---|
| 35 |  | 
|---|
| 36 | namespace capnp { | 
|---|
| 37 |  | 
|---|
| 38 | class Schema; | 
|---|
| 39 | class StructSchema; | 
|---|
| 40 | class EnumSchema; | 
|---|
| 41 | class InterfaceSchema; | 
|---|
| 42 | class ConstSchema; | 
|---|
| 43 | class ListSchema; | 
|---|
| 44 | class Type; | 
|---|
| 45 |  | 
|---|
| 46 | template <typename T, Kind k = kind<T>()> struct SchemaType_ { typedef Schema Type; }; | 
|---|
| 47 | template <typename T> struct SchemaType_<T, Kind::PRIMITIVE> { typedef schema::Type::Which Type; }; | 
|---|
| 48 | template <typename T> struct SchemaType_<T, Kind::BLOB> { typedef schema::Type::Which Type; }; | 
|---|
| 49 | template <typename T> struct SchemaType_<T, Kind::ENUM> { typedef EnumSchema Type; }; | 
|---|
| 50 | template <typename T> struct SchemaType_<T, Kind::STRUCT> { typedef StructSchema Type; }; | 
|---|
| 51 | template <typename T> struct SchemaType_<T, Kind::INTERFACE> { typedef InterfaceSchema Type; }; | 
|---|
| 52 | template <typename T> struct SchemaType_<T, Kind::LIST> { typedef ListSchema Type; }; | 
|---|
| 53 |  | 
|---|
| 54 | template <typename T> | 
|---|
| 55 | using SchemaType = typename SchemaType_<T>::Type; | 
|---|
| 56 | // SchemaType<T> is the type of T's schema, e.g. StructSchema if T is a struct. | 
|---|
| 57 |  | 
|---|
| 58 | namespace _ {  // private | 
|---|
| 59 | extern const RawSchema NULL_SCHEMA; | 
|---|
| 60 | extern const RawSchema NULL_STRUCT_SCHEMA; | 
|---|
| 61 | extern const RawSchema NULL_ENUM_SCHEMA; | 
|---|
| 62 | extern const RawSchema NULL_INTERFACE_SCHEMA; | 
|---|
| 63 | extern const RawSchema NULL_CONST_SCHEMA; | 
|---|
| 64 | // The schema types default to these null (empty) schemas in case of error, especially when | 
|---|
| 65 | // exceptions are disabled. | 
|---|
| 66 | }  // namespace _ (private) | 
|---|
| 67 |  | 
|---|
| 68 | class Schema { | 
|---|
| 69 | // Convenience wrapper around capnp::schema::Node. | 
|---|
| 70 |  | 
|---|
| 71 | public: | 
|---|
| 72 | inline Schema(): raw(&_::NULL_SCHEMA.defaultBrand) {} | 
|---|
| 73 |  | 
|---|
| 74 | template <typename T> | 
|---|
| 75 | static inline SchemaType<T> from() { return SchemaType<T>::template fromImpl<T>(); } | 
|---|
| 76 | // Get the Schema for a particular compiled-in type. | 
|---|
| 77 |  | 
|---|
| 78 | schema::Node::Reader getProto() const; | 
|---|
| 79 | // Get the underlying Cap'n Proto representation of the schema node.  (Note that this accessor | 
|---|
| 80 | // has performance comparable to accessors of struct-typed fields on Reader classes.) | 
|---|
| 81 |  | 
|---|
| 82 | kj::ArrayPtr<const word> asUncheckedMessage() const; | 
|---|
| 83 | // Get the encoded schema node content as a single message segment.  It is safe to read as an | 
|---|
| 84 | // unchecked message. | 
|---|
| 85 |  | 
|---|
| 86 | Schema getDependency(uint64_t id) const CAPNP_DEPRECATED( "Does not handle generics correctly."); | 
|---|
| 87 | // DEPRECATED: This method cannot correctly account for generic type parameter bindings that | 
|---|
| 88 | //   may apply to the dependency. Instead of using this method, use a method of the Schema API | 
|---|
| 89 | //   that corresponds to the exact kind of dependency. For example, to get a field type, use | 
|---|
| 90 | //   StructSchema::Field::getType(). | 
|---|
| 91 | // | 
|---|
| 92 | // Gets the Schema for one of this Schema's dependencies.  For example, if this Schema is for a | 
|---|
| 93 | // struct, you could look up the schema for one of its fields' types.  Throws an exception if this | 
|---|
| 94 | // schema doesn't actually depend on the given id. | 
|---|
| 95 | // | 
|---|
| 96 | // Note that not all type IDs found in the schema node are considered "dependencies" -- only the | 
|---|
| 97 | // ones that are needed to implement the dynamic API are.  That includes: | 
|---|
| 98 | // - Field types. | 
|---|
| 99 | // - Group types. | 
|---|
| 100 | // - scopeId for group nodes, but NOT otherwise. | 
|---|
| 101 | // - Method parameter and return types. | 
|---|
| 102 | // | 
|---|
| 103 | // The following are NOT considered dependencies: | 
|---|
| 104 | // - Nested nodes. | 
|---|
| 105 | // - scopeId for a non-group node. | 
|---|
| 106 | // - Annotations. | 
|---|
| 107 | // | 
|---|
| 108 | // To obtain schemas for those, you would need a SchemaLoader. | 
|---|
| 109 |  | 
|---|
| 110 | bool isBranded() const; | 
|---|
| 111 | // Returns true if this schema represents a non-default parameterization of this type. | 
|---|
| 112 |  | 
|---|
| 113 | Schema getGeneric() const; | 
|---|
| 114 | // Get the version of this schema with any brands removed. | 
|---|
| 115 |  | 
|---|
| 116 | class BrandArgumentList; | 
|---|
| 117 | BrandArgumentList getBrandArgumentsAtScope(uint64_t scopeId) const; | 
|---|
| 118 | // Gets the values bound to the brand parameters at the given scope. | 
|---|
| 119 |  | 
|---|
| 120 | StructSchema asStruct() const; | 
|---|
| 121 | EnumSchema asEnum() const; | 
|---|
| 122 | InterfaceSchema asInterface() const; | 
|---|
| 123 | ConstSchema asConst() const; | 
|---|
| 124 | // Cast the Schema to a specific type.  Throws an exception if the type doesn't match.  Use | 
|---|
| 125 | // getProto() to determine type, e.g. getProto().isStruct(). | 
|---|
| 126 |  | 
|---|
| 127 | inline bool operator==(const Schema& other) const { return raw == other.raw; } | 
|---|
| 128 | inline bool operator!=(const Schema& other) const { return raw != other.raw; } | 
|---|
| 129 | // Determine whether two Schemas are wrapping the exact same underlying data, by identity.  If | 
|---|
| 130 | // you want to check if two Schemas represent the same type (but possibly different versions of | 
|---|
| 131 | // it), compare their IDs instead. | 
|---|
| 132 |  | 
|---|
| 133 | inline uint hashCode() const { return kj::hashCode(raw); } | 
|---|
| 134 |  | 
|---|
| 135 | template <typename T> | 
|---|
| 136 | void requireUsableAs() const; | 
|---|
| 137 | // Throws an exception if a value with this Schema cannot safely be cast to a native value of | 
|---|
| 138 | // the given type.  This passes if either: | 
|---|
| 139 | // - *this == from<T>() | 
|---|
| 140 | // - This schema was loaded with SchemaLoader, the type ID matches typeId<T>(), and | 
|---|
| 141 | //   loadCompiledTypeAndDependencies<T>() was called on the SchemaLoader. | 
|---|
| 142 |  | 
|---|
| 143 | kj::StringPtr getShortDisplayName() const; | 
|---|
| 144 | // Get the short version of the node's display name. | 
|---|
| 145 |  | 
|---|
| 146 | private: | 
|---|
| 147 | const _::RawBrandedSchema* raw; | 
|---|
| 148 |  | 
|---|
| 149 | inline explicit Schema(const _::RawBrandedSchema* raw): raw(raw) { | 
|---|
| 150 | KJ_IREQUIRE(raw->lazyInitializer == nullptr, | 
|---|
| 151 | "Must call ensureInitialized() on RawSchema before constructing Schema."); | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 | template <typename T> static inline Schema fromImpl() { | 
|---|
| 155 | return Schema(&_::rawSchema<T>()); | 
|---|
| 156 | } | 
|---|
| 157 |  | 
|---|
| 158 | void requireUsableAs(const _::RawSchema* expected) const; | 
|---|
| 159 |  | 
|---|
| 160 | uint32_t getSchemaOffset(const schema::Value::Reader& value) const; | 
|---|
| 161 |  | 
|---|
| 162 | Type getBrandBinding(uint64_t scopeId, uint index) const; | 
|---|
| 163 | // Look up the binding for a brand parameter used by this Schema. Returns `AnyPointer` if the | 
|---|
| 164 | // parameter is not bound. | 
|---|
| 165 | // | 
|---|
| 166 | // TODO(someday): Public interface for iterating over all bindings? | 
|---|
| 167 |  | 
|---|
| 168 | Schema getDependency(uint64_t id, uint location) const; | 
|---|
| 169 | // Look up schema for a particular dependency of this schema. `location` is the dependency | 
|---|
| 170 | // location number as defined in _::RawBrandedSchema. | 
|---|
| 171 |  | 
|---|
| 172 | Type interpretType(schema::Type::Reader proto, uint location) const; | 
|---|
| 173 | // Interpret a schema::Type in the given location within the schema, compiling it into a | 
|---|
| 174 | // Type object. | 
|---|
| 175 |  | 
|---|
| 176 | friend class StructSchema; | 
|---|
| 177 | friend class EnumSchema; | 
|---|
| 178 | friend class InterfaceSchema; | 
|---|
| 179 | friend class ConstSchema; | 
|---|
| 180 | friend class ListSchema; | 
|---|
| 181 | friend class SchemaLoader; | 
|---|
| 182 | friend class Type; | 
|---|
| 183 | friend kj::StringTree _::structString( | 
|---|
| 184 | _::StructReader reader, const _::RawBrandedSchema& schema); | 
|---|
| 185 | friend kj::String _::enumString(uint16_t value, const _::RawBrandedSchema& schema); | 
|---|
| 186 | }; | 
|---|
| 187 |  | 
|---|
| 188 | kj::StringPtr KJ_STRINGIFY(const Schema& schema); | 
|---|
| 189 |  | 
|---|
| 190 | class Schema::BrandArgumentList { | 
|---|
| 191 | // A list of generic parameter bindings for parameters of some particular type. Note that since | 
|---|
| 192 | // parameters on an outer type apply to all inner types as well, a deeply-nested type can have | 
|---|
| 193 | // multiple BrandArgumentLists that apply to it. | 
|---|
| 194 | // | 
|---|
| 195 | // A BrandArgumentList only represents the arguments that the client of the type specified. Since | 
|---|
| 196 | // new parameters can be added over time, this list may not cover all defined parameters for the | 
|---|
| 197 | // type. Missing parameters should be treated as AnyPointer. This class's implementation of | 
|---|
| 198 | // operator[] already does this for you; out-of-bounds access will safely return AnyPointer. | 
|---|
| 199 |  | 
|---|
| 200 | public: | 
|---|
| 201 | inline BrandArgumentList(): scopeId(0), size_(0), bindings(nullptr) {} | 
|---|
| 202 |  | 
|---|
| 203 | inline uint size() const { return size_; } | 
|---|
| 204 | Type operator[](uint index) const; | 
|---|
| 205 |  | 
|---|
| 206 | typedef _::IndexingIterator<const BrandArgumentList, Type> Iterator; | 
|---|
| 207 | inline Iterator begin() const { return Iterator(this, 0); } | 
|---|
| 208 | inline Iterator end() const { return Iterator(this, size()); } | 
|---|
| 209 |  | 
|---|
| 210 | private: | 
|---|
| 211 | uint64_t scopeId; | 
|---|
| 212 | uint size_; | 
|---|
| 213 | bool isUnbound; | 
|---|
| 214 | const _::RawBrandedSchema::Binding* bindings; | 
|---|
| 215 |  | 
|---|
| 216 | inline BrandArgumentList(uint64_t scopeId, bool isUnbound) | 
|---|
| 217 | : scopeId(scopeId), size_(0), isUnbound(isUnbound), bindings(nullptr) {} | 
|---|
| 218 | inline BrandArgumentList(uint64_t scopeId, uint size, | 
|---|
| 219 | const _::RawBrandedSchema::Binding* bindings) | 
|---|
| 220 | : scopeId(scopeId), size_(size), isUnbound(false), bindings(bindings) {} | 
|---|
| 221 |  | 
|---|
| 222 | friend class Schema; | 
|---|
| 223 | }; | 
|---|
| 224 |  | 
|---|
| 225 | // ------------------------------------------------------------------- | 
|---|
| 226 |  | 
|---|
| 227 | class StructSchema: public Schema { | 
|---|
| 228 | public: | 
|---|
| 229 | inline StructSchema(): Schema(&_::NULL_STRUCT_SCHEMA.defaultBrand) {} | 
|---|
| 230 |  | 
|---|
| 231 | class Field; | 
|---|
| 232 | class FieldList; | 
|---|
| 233 | class FieldSubset; | 
|---|
| 234 |  | 
|---|
| 235 | FieldList getFields() const; | 
|---|
| 236 | // List top-level fields of this struct.  This list will contain top-level groups (including | 
|---|
| 237 | // named unions) but not the members of those groups.  The list does, however, contain the | 
|---|
| 238 | // members of the unnamed union, if there is one. | 
|---|
| 239 |  | 
|---|
| 240 | FieldSubset getUnionFields() const; | 
|---|
| 241 | // If the field contains an unnamed union, get a list of fields in the union, ordered by | 
|---|
| 242 | // ordinal.  Since discriminant values are assigned sequentially by ordinal, you may index this | 
|---|
| 243 | // list by discriminant value. | 
|---|
| 244 |  | 
|---|
| 245 | FieldSubset getNonUnionFields() const; | 
|---|
| 246 | // Get the fields of this struct which are not in an unnamed union, ordered by ordinal. | 
|---|
| 247 |  | 
|---|
| 248 | kj::Maybe<Field> findFieldByName(kj::StringPtr name) const; | 
|---|
| 249 | // Find the field with the given name, or return null if there is no such field.  If the struct | 
|---|
| 250 | // contains an unnamed union, then this will find fields of that union in addition to fields | 
|---|
| 251 | // of the outer struct, since they exist in the same namespace.  It will not, however, find | 
|---|
| 252 | // members of groups (including named unions) -- you must first look up the group itself, | 
|---|
| 253 | // then dig into its type. | 
|---|
| 254 |  | 
|---|
| 255 | Field getFieldByName(kj::StringPtr name) const; | 
|---|
| 256 | // Like findFieldByName() but throws an exception on failure. | 
|---|
| 257 |  | 
|---|
| 258 | kj::Maybe<Field> getFieldByDiscriminant(uint16_t discriminant) const; | 
|---|
| 259 | // Finds the field whose `discriminantValue` is equal to the given value, or returns null if | 
|---|
| 260 | // there is no such field.  (If the schema does not represent a union or a struct containing | 
|---|
| 261 | // an unnamed union, then this always returns null.) | 
|---|
| 262 |  | 
|---|
| 263 | private: | 
|---|
| 264 | StructSchema(Schema base): Schema(base) {} | 
|---|
| 265 | template <typename T> static inline StructSchema fromImpl() { | 
|---|
| 266 | return StructSchema(Schema(&_::rawBrandedSchema<T>())); | 
|---|
| 267 | } | 
|---|
| 268 | friend class Schema; | 
|---|
| 269 | friend class Type; | 
|---|
| 270 | }; | 
|---|
| 271 |  | 
|---|
| 272 | class StructSchema::Field { | 
|---|
| 273 | public: | 
|---|
| 274 | Field() = default; | 
|---|
| 275 |  | 
|---|
| 276 | inline schema::Field::Reader getProto() const { return proto; } | 
|---|
| 277 | inline StructSchema getContainingStruct() const { return parent; } | 
|---|
| 278 |  | 
|---|
| 279 | inline uint getIndex() const { return index; } | 
|---|
| 280 | // Get the index of this field within the containing struct or union. | 
|---|
| 281 |  | 
|---|
| 282 | Type getType() const; | 
|---|
| 283 | // Get the type of this field. Note that this is preferred over getProto().getType() as this | 
|---|
| 284 | // method will apply generics. | 
|---|
| 285 |  | 
|---|
| 286 | uint32_t getDefaultValueSchemaOffset() const; | 
|---|
| 287 | // For struct, list, and object fields, returns the offset, in words, within the first segment of | 
|---|
| 288 | // the struct's schema, where this field's default value pointer is located.  The schema is | 
|---|
| 289 | // always stored as a single-segment unchecked message, which in turn means that the default | 
|---|
| 290 | // value pointer itself can be treated as the root of an unchecked message -- if you know where | 
|---|
| 291 | // to find it, which is what this method helps you with. | 
|---|
| 292 | // | 
|---|
| 293 | // For blobs, returns the offset of the beginning of the blob's content within the first segment | 
|---|
| 294 | // of the struct's schema. | 
|---|
| 295 | // | 
|---|
| 296 | // This is primarily useful for code generators.  The C++ code generator, for example, embeds | 
|---|
| 297 | // the entire schema as a raw word array within the generated code.  Of course, to implement | 
|---|
| 298 | // field accessors, it needs access to those fields' default values.  Embedding separate copies | 
|---|
| 299 | // of those default values would be redundant since they are already included in the schema, but | 
|---|
| 300 | // seeking through the schema at runtime to find the default values would be ugly.  Instead, | 
|---|
| 301 | // the code generator can use getDefaultValueSchemaOffset() to find the offset of the default | 
|---|
| 302 | // value within the schema, and can simply apply that offset at runtime. | 
|---|
| 303 | // | 
|---|
| 304 | // If the above does not make sense, you probably don't need this method. | 
|---|
| 305 |  | 
|---|
| 306 | inline bool operator==(const Field& other) const; | 
|---|
| 307 | inline bool operator!=(const Field& other) const { return !(*this == other); } | 
|---|
| 308 | inline uint hashCode() const; | 
|---|
| 309 |  | 
|---|
| 310 | private: | 
|---|
| 311 | StructSchema parent; | 
|---|
| 312 | uint index; | 
|---|
| 313 | schema::Field::Reader proto; | 
|---|
| 314 |  | 
|---|
| 315 | inline Field(StructSchema parent, uint index, schema::Field::Reader proto) | 
|---|
| 316 | : parent(parent), index(index), proto(proto) {} | 
|---|
| 317 |  | 
|---|
| 318 | friend class StructSchema; | 
|---|
| 319 | }; | 
|---|
| 320 |  | 
|---|
| 321 | kj::StringPtr KJ_STRINGIFY(const StructSchema::Field& field); | 
|---|
| 322 |  | 
|---|
| 323 | class StructSchema::FieldList { | 
|---|
| 324 | public: | 
|---|
| 325 | FieldList() = default;  // empty list | 
|---|
| 326 |  | 
|---|
| 327 | inline uint size() const { return list.size(); } | 
|---|
| 328 | inline Field operator[](uint index) const { return Field(parent, index, list[index]); } | 
|---|
| 329 |  | 
|---|
| 330 | typedef _::IndexingIterator<const FieldList, Field> Iterator; | 
|---|
| 331 | inline Iterator begin() const { return Iterator(this, 0); } | 
|---|
| 332 | inline Iterator end() const { return Iterator(this, size()); } | 
|---|
| 333 |  | 
|---|
| 334 | private: | 
|---|
| 335 | StructSchema parent; | 
|---|
| 336 | List<schema::Field>::Reader list; | 
|---|
| 337 |  | 
|---|
| 338 | inline FieldList(StructSchema parent, List<schema::Field>::Reader list) | 
|---|
| 339 | : parent(parent), list(list) {} | 
|---|
| 340 |  | 
|---|
| 341 | friend class StructSchema; | 
|---|
| 342 | }; | 
|---|
| 343 |  | 
|---|
| 344 | class StructSchema::FieldSubset { | 
|---|
| 345 | public: | 
|---|
| 346 | FieldSubset() = default;  // empty list | 
|---|
| 347 |  | 
|---|
| 348 | inline uint size() const { return size_; } | 
|---|
| 349 | inline Field operator[](uint index) const { | 
|---|
| 350 | return Field(parent, indices[index], list[indices[index]]); | 
|---|
| 351 | } | 
|---|
| 352 |  | 
|---|
| 353 | typedef _::IndexingIterator<const FieldSubset, Field> Iterator; | 
|---|
| 354 | inline Iterator begin() const { return Iterator(this, 0); } | 
|---|
| 355 | inline Iterator end() const { return Iterator(this, size()); } | 
|---|
| 356 |  | 
|---|
| 357 | private: | 
|---|
| 358 | StructSchema parent; | 
|---|
| 359 | List<schema::Field>::Reader list; | 
|---|
| 360 | const uint16_t* indices; | 
|---|
| 361 | uint size_; | 
|---|
| 362 |  | 
|---|
| 363 | inline FieldSubset(StructSchema parent, List<schema::Field>::Reader list, | 
|---|
| 364 | const uint16_t* indices, uint size) | 
|---|
| 365 | : parent(parent), list(list), indices(indices), size_(size) {} | 
|---|
| 366 |  | 
|---|
| 367 | friend class StructSchema; | 
|---|
| 368 | }; | 
|---|
| 369 |  | 
|---|
| 370 | // ------------------------------------------------------------------- | 
|---|
| 371 |  | 
|---|
| 372 | class EnumSchema: public Schema { | 
|---|
| 373 | public: | 
|---|
| 374 | inline EnumSchema(): Schema(&_::NULL_ENUM_SCHEMA.defaultBrand) {} | 
|---|
| 375 |  | 
|---|
| 376 | class Enumerant; | 
|---|
| 377 | class EnumerantList; | 
|---|
| 378 |  | 
|---|
| 379 | EnumerantList getEnumerants() const; | 
|---|
| 380 |  | 
|---|
| 381 | kj::Maybe<Enumerant> findEnumerantByName(kj::StringPtr name) const; | 
|---|
| 382 |  | 
|---|
| 383 | Enumerant getEnumerantByName(kj::StringPtr name) const; | 
|---|
| 384 | // Like findEnumerantByName() but throws an exception on failure. | 
|---|
| 385 |  | 
|---|
| 386 | private: | 
|---|
| 387 | EnumSchema(Schema base): Schema(base) {} | 
|---|
| 388 | template <typename T> static inline EnumSchema fromImpl() { | 
|---|
| 389 | return EnumSchema(Schema(&_::rawBrandedSchema<T>())); | 
|---|
| 390 | } | 
|---|
| 391 | friend class Schema; | 
|---|
| 392 | friend class Type; | 
|---|
| 393 | }; | 
|---|
| 394 |  | 
|---|
| 395 | class EnumSchema::Enumerant { | 
|---|
| 396 | public: | 
|---|
| 397 | Enumerant() = default; | 
|---|
| 398 |  | 
|---|
| 399 | inline schema::Enumerant::Reader getProto() const { return proto; } | 
|---|
| 400 | inline EnumSchema getContainingEnum() const { return parent; } | 
|---|
| 401 |  | 
|---|
| 402 | inline uint16_t getOrdinal() const { return ordinal; } | 
|---|
| 403 | inline uint getIndex() const { return ordinal; } | 
|---|
| 404 |  | 
|---|
| 405 | inline bool operator==(const Enumerant& other) const; | 
|---|
| 406 | inline bool operator!=(const Enumerant& other) const { return !(*this == other); } | 
|---|
| 407 | inline uint hashCode() const; | 
|---|
| 408 |  | 
|---|
| 409 | private: | 
|---|
| 410 | EnumSchema parent; | 
|---|
| 411 | uint16_t ordinal; | 
|---|
| 412 | schema::Enumerant::Reader proto; | 
|---|
| 413 |  | 
|---|
| 414 | inline Enumerant(EnumSchema parent, uint16_t ordinal, schema::Enumerant::Reader proto) | 
|---|
| 415 | : parent(parent), ordinal(ordinal), proto(proto) {} | 
|---|
| 416 |  | 
|---|
| 417 | friend class EnumSchema; | 
|---|
| 418 | }; | 
|---|
| 419 |  | 
|---|
| 420 | class EnumSchema::EnumerantList { | 
|---|
| 421 | public: | 
|---|
| 422 | EnumerantList() = default;  // empty list | 
|---|
| 423 |  | 
|---|
| 424 | inline uint size() const { return list.size(); } | 
|---|
| 425 | inline Enumerant operator[](uint index) const { return Enumerant(parent, index, list[index]); } | 
|---|
| 426 |  | 
|---|
| 427 | typedef _::IndexingIterator<const EnumerantList, Enumerant> Iterator; | 
|---|
| 428 | inline Iterator begin() const { return Iterator(this, 0); } | 
|---|
| 429 | inline Iterator end() const { return Iterator(this, size()); } | 
|---|
| 430 |  | 
|---|
| 431 | private: | 
|---|
| 432 | EnumSchema parent; | 
|---|
| 433 | List<schema::Enumerant>::Reader list; | 
|---|
| 434 |  | 
|---|
| 435 | inline EnumerantList(EnumSchema parent, List<schema::Enumerant>::Reader list) | 
|---|
| 436 | : parent(parent), list(list) {} | 
|---|
| 437 |  | 
|---|
| 438 | friend class EnumSchema; | 
|---|
| 439 | }; | 
|---|
| 440 |  | 
|---|
| 441 | // ------------------------------------------------------------------- | 
|---|
| 442 |  | 
|---|
| 443 | class InterfaceSchema: public Schema { | 
|---|
| 444 | public: | 
|---|
| 445 | inline InterfaceSchema(): Schema(&_::NULL_INTERFACE_SCHEMA.defaultBrand) {} | 
|---|
| 446 |  | 
|---|
| 447 | class Method; | 
|---|
| 448 | class MethodList; | 
|---|
| 449 |  | 
|---|
| 450 | MethodList getMethods() const; | 
|---|
| 451 |  | 
|---|
| 452 | kj::Maybe<Method> findMethodByName(kj::StringPtr name) const; | 
|---|
| 453 |  | 
|---|
| 454 | Method getMethodByName(kj::StringPtr name) const; | 
|---|
| 455 | // Like findMethodByName() but throws an exception on failure. | 
|---|
| 456 |  | 
|---|
| 457 | class SuperclassList; | 
|---|
| 458 |  | 
|---|
| 459 | SuperclassList getSuperclasses() const; | 
|---|
| 460 | // Get the immediate superclasses of this type, after applying generics. | 
|---|
| 461 |  | 
|---|
| 462 | bool extends(InterfaceSchema other) const; | 
|---|
| 463 | // Returns true if `other` is a superclass of this interface (including if `other == *this`). | 
|---|
| 464 |  | 
|---|
| 465 | kj::Maybe<InterfaceSchema> findSuperclass(uint64_t typeId) const; | 
|---|
| 466 | // Find the superclass of this interface with the given type ID.  Returns null if the interface | 
|---|
| 467 | // extends no such type. | 
|---|
| 468 |  | 
|---|
| 469 | private: | 
|---|
| 470 | InterfaceSchema(Schema base): Schema(base) {} | 
|---|
| 471 | template <typename T> static inline InterfaceSchema fromImpl() { | 
|---|
| 472 | return InterfaceSchema(Schema(&_::rawBrandedSchema<T>())); | 
|---|
| 473 | } | 
|---|
| 474 | friend class Schema; | 
|---|
| 475 | friend class Type; | 
|---|
| 476 |  | 
|---|
| 477 | kj::Maybe<Method> findMethodByName(kj::StringPtr name, uint& counter) const; | 
|---|
| 478 | bool extends(InterfaceSchema other, uint& counter) const; | 
|---|
| 479 | kj::Maybe<InterfaceSchema> findSuperclass(uint64_t typeId, uint& counter) const; | 
|---|
| 480 | // We protect against malicious schemas with large or cyclic hierarchies by cutting off the | 
|---|
| 481 | // search when the counter reaches a threshold. | 
|---|
| 482 | }; | 
|---|
| 483 |  | 
|---|
| 484 | class InterfaceSchema::Method { | 
|---|
| 485 | public: | 
|---|
| 486 | Method() = default; | 
|---|
| 487 |  | 
|---|
| 488 | inline schema::Method::Reader getProto() const { return proto; } | 
|---|
| 489 | inline InterfaceSchema getContainingInterface() const { return parent; } | 
|---|
| 490 |  | 
|---|
| 491 | inline uint16_t getOrdinal() const { return ordinal; } | 
|---|
| 492 | inline uint getIndex() const { return ordinal; } | 
|---|
| 493 |  | 
|---|
| 494 | StructSchema getParamType() const; | 
|---|
| 495 | StructSchema getResultType() const; | 
|---|
| 496 | // Get the parameter and result types, including substituting generic parameters. | 
|---|
| 497 |  | 
|---|
| 498 | inline bool operator==(const Method& other) const; | 
|---|
| 499 | inline bool operator!=(const Method& other) const { return !(*this == other); } | 
|---|
| 500 | inline uint hashCode() const; | 
|---|
| 501 |  | 
|---|
| 502 | private: | 
|---|
| 503 | InterfaceSchema parent; | 
|---|
| 504 | uint16_t ordinal; | 
|---|
| 505 | schema::Method::Reader proto; | 
|---|
| 506 |  | 
|---|
| 507 | inline Method(InterfaceSchema parent, uint16_t ordinal, | 
|---|
| 508 | schema::Method::Reader proto) | 
|---|
| 509 | : parent(parent), ordinal(ordinal), proto(proto) {} | 
|---|
| 510 |  | 
|---|
| 511 | friend class InterfaceSchema; | 
|---|
| 512 | }; | 
|---|
| 513 |  | 
|---|
| 514 | class InterfaceSchema::MethodList { | 
|---|
| 515 | public: | 
|---|
| 516 | MethodList() = default;  // empty list | 
|---|
| 517 |  | 
|---|
| 518 | inline uint size() const { return list.size(); } | 
|---|
| 519 | inline Method operator[](uint index) const { return Method(parent, index, list[index]); } | 
|---|
| 520 |  | 
|---|
| 521 | typedef _::IndexingIterator<const MethodList, Method> Iterator; | 
|---|
| 522 | inline Iterator begin() const { return Iterator(this, 0); } | 
|---|
| 523 | inline Iterator end() const { return Iterator(this, size()); } | 
|---|
| 524 |  | 
|---|
| 525 | private: | 
|---|
| 526 | InterfaceSchema parent; | 
|---|
| 527 | List<schema::Method>::Reader list; | 
|---|
| 528 |  | 
|---|
| 529 | inline MethodList(InterfaceSchema parent, List<schema::Method>::Reader list) | 
|---|
| 530 | : parent(parent), list(list) {} | 
|---|
| 531 |  | 
|---|
| 532 | friend class InterfaceSchema; | 
|---|
| 533 | }; | 
|---|
| 534 |  | 
|---|
| 535 | class InterfaceSchema::SuperclassList { | 
|---|
| 536 | public: | 
|---|
| 537 | SuperclassList() = default;  // empty list | 
|---|
| 538 |  | 
|---|
| 539 | inline uint size() const { return list.size(); } | 
|---|
| 540 | InterfaceSchema operator[](uint index) const; | 
|---|
| 541 |  | 
|---|
| 542 | typedef _::IndexingIterator<const SuperclassList, InterfaceSchema> Iterator; | 
|---|
| 543 | inline Iterator begin() const { return Iterator(this, 0); } | 
|---|
| 544 | inline Iterator end() const { return Iterator(this, size()); } | 
|---|
| 545 |  | 
|---|
| 546 | private: | 
|---|
| 547 | InterfaceSchema parent; | 
|---|
| 548 | List<schema::Superclass>::Reader list; | 
|---|
| 549 |  | 
|---|
| 550 | inline SuperclassList(InterfaceSchema parent, List<schema::Superclass>::Reader list) | 
|---|
| 551 | : parent(parent), list(list) {} | 
|---|
| 552 |  | 
|---|
| 553 | friend class InterfaceSchema; | 
|---|
| 554 | }; | 
|---|
| 555 |  | 
|---|
| 556 | // ------------------------------------------------------------------- | 
|---|
| 557 |  | 
|---|
| 558 | class ConstSchema: public Schema { | 
|---|
| 559 | // Represents a constant declaration. | 
|---|
| 560 | // | 
|---|
| 561 | // `ConstSchema` can be implicitly cast to DynamicValue to read its value. | 
|---|
| 562 |  | 
|---|
| 563 | public: | 
|---|
| 564 | inline ConstSchema(): Schema(&_::NULL_CONST_SCHEMA.defaultBrand) {} | 
|---|
| 565 |  | 
|---|
| 566 | template <typename T> | 
|---|
| 567 | ReaderFor<T> as() const; | 
|---|
| 568 | // Read the constant's value.  This is a convenience method equivalent to casting the ConstSchema | 
|---|
| 569 | // to a DynamicValue and then calling its `as<T>()` method.  For dependency reasons, this method | 
|---|
| 570 | // is defined in <capnp/dynamic.h>, which you must #include explicitly. | 
|---|
| 571 |  | 
|---|
| 572 | uint32_t getValueSchemaOffset() const; | 
|---|
| 573 | // Much like StructSchema::Field::getDefaultValueSchemaOffset(), if the constant has pointer | 
|---|
| 574 | // type, this gets the offset from the beginning of the constant's schema node to a pointer | 
|---|
| 575 | // representing the constant value. | 
|---|
| 576 |  | 
|---|
| 577 | Type getType() const; | 
|---|
| 578 |  | 
|---|
| 579 | private: | 
|---|
| 580 | ConstSchema(Schema base): Schema(base) {} | 
|---|
| 581 | friend class Schema; | 
|---|
| 582 | }; | 
|---|
| 583 |  | 
|---|
| 584 | // ------------------------------------------------------------------- | 
|---|
| 585 |  | 
|---|
| 586 | class Type { | 
|---|
| 587 | public: | 
|---|
| 588 | struct BrandParameter { | 
|---|
| 589 | uint64_t scopeId; | 
|---|
| 590 | uint index; | 
|---|
| 591 | }; | 
|---|
| 592 | struct ImplicitParameter { | 
|---|
| 593 | uint index; | 
|---|
| 594 | }; | 
|---|
| 595 |  | 
|---|
| 596 | inline Type(); | 
|---|
| 597 | inline Type(schema::Type::Which primitive); | 
|---|
| 598 | inline Type(StructSchema schema); | 
|---|
| 599 | inline Type(EnumSchema schema); | 
|---|
| 600 | inline Type(InterfaceSchema schema); | 
|---|
| 601 | inline Type(ListSchema schema); | 
|---|
| 602 | inline Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind); | 
|---|
| 603 | inline Type(BrandParameter param); | 
|---|
| 604 | inline Type(ImplicitParameter param); | 
|---|
| 605 |  | 
|---|
| 606 | template <typename T> | 
|---|
| 607 | inline static Type from(); | 
|---|
| 608 | template <typename T> | 
|---|
| 609 | inline static Type from(T&& value); | 
|---|
| 610 |  | 
|---|
| 611 | inline schema::Type::Which which() const; | 
|---|
| 612 |  | 
|---|
| 613 | StructSchema asStruct() const; | 
|---|
| 614 | EnumSchema asEnum() const; | 
|---|
| 615 | InterfaceSchema asInterface() const; | 
|---|
| 616 | ListSchema asList() const; | 
|---|
| 617 | // Each of these methods may only be called if which() returns the corresponding type. | 
|---|
| 618 |  | 
|---|
| 619 | kj::Maybe<BrandParameter> getBrandParameter() const; | 
|---|
| 620 | // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular | 
|---|
| 621 | // AnyPointer and not a parameter. | 
|---|
| 622 |  | 
|---|
| 623 | kj::Maybe<ImplicitParameter> getImplicitParameter() const; | 
|---|
| 624 | // Only callable if which() returns ANY_POINTER. Returns null if the type is just a regular | 
|---|
| 625 | // AnyPointer and not a parameter. "Implicit parameters" refer to type parameters on methods. | 
|---|
| 626 |  | 
|---|
| 627 | inline schema::Type::AnyPointer::Unconstrained::Which whichAnyPointerKind() const; | 
|---|
| 628 | // Only callable if which() returns ANY_POINTER. | 
|---|
| 629 |  | 
|---|
| 630 | inline bool isVoid() const; | 
|---|
| 631 | inline bool isBool() const; | 
|---|
| 632 | inline bool isInt8() const; | 
|---|
| 633 | inline bool isInt16() const; | 
|---|
| 634 | inline bool isInt32() const; | 
|---|
| 635 | inline bool isInt64() const; | 
|---|
| 636 | inline bool isUInt8() const; | 
|---|
| 637 | inline bool isUInt16() const; | 
|---|
| 638 | inline bool isUInt32() const; | 
|---|
| 639 | inline bool isUInt64() const; | 
|---|
| 640 | inline bool isFloat32() const; | 
|---|
| 641 | inline bool isFloat64() const; | 
|---|
| 642 | inline bool isText() const; | 
|---|
| 643 | inline bool isData() const; | 
|---|
| 644 | inline bool isList() const; | 
|---|
| 645 | inline bool isEnum() const; | 
|---|
| 646 | inline bool isStruct() const; | 
|---|
| 647 | inline bool isInterface() const; | 
|---|
| 648 | inline bool isAnyPointer() const; | 
|---|
| 649 |  | 
|---|
| 650 | bool operator==(const Type& other) const; | 
|---|
| 651 | inline bool operator!=(const Type& other) const { return !(*this == other); } | 
|---|
| 652 |  | 
|---|
| 653 | uint hashCode() const; | 
|---|
| 654 |  | 
|---|
| 655 | inline Type wrapInList(uint depth = 1) const; | 
|---|
| 656 | // Return the Type formed by wrapping this type in List() `depth` times. | 
|---|
| 657 |  | 
|---|
| 658 | inline Type(schema::Type::Which derived, const _::RawBrandedSchema* schema); | 
|---|
| 659 | // For internal use. | 
|---|
| 660 |  | 
|---|
| 661 | private: | 
|---|
| 662 | schema::Type::Which baseType;  // type not including applications of List() | 
|---|
| 663 | uint8_t listDepth;             // 0 for T, 1 for List(T), 2 for List(List(T)), ... | 
|---|
| 664 |  | 
|---|
| 665 | bool isImplicitParam; | 
|---|
| 666 | // If true, this refers to an implicit method parameter. baseType must be ANY_POINTER, scopeId | 
|---|
| 667 | // must be zero, and paramIndex indicates the parameter index. | 
|---|
| 668 |  | 
|---|
| 669 | union { | 
|---|
| 670 | uint16_t paramIndex; | 
|---|
| 671 | // If baseType is ANY_POINTER but this Type actually refers to a type parameter, this is the | 
|---|
| 672 | // index of the parameter among the parameters at its scope, and `scopeId` below is the type ID | 
|---|
| 673 | // of the scope where the parameter was defined. | 
|---|
| 674 |  | 
|---|
| 675 | schema::Type::AnyPointer::Unconstrained::Which anyPointerKind; | 
|---|
| 676 | // If scopeId is zero and isImplicitParam is false. | 
|---|
| 677 | }; | 
|---|
| 678 |  | 
|---|
| 679 | union { | 
|---|
| 680 | const _::RawBrandedSchema* schema;  // if type is struct, enum, interface... | 
|---|
| 681 | uint64_t scopeId;  // if type is AnyPointer but it's actually a type parameter... | 
|---|
| 682 | }; | 
|---|
| 683 |  | 
|---|
| 684 | Type(schema::Type::Which baseType, uint8_t listDepth, const _::RawBrandedSchema* schema) | 
|---|
| 685 | : baseType(baseType), listDepth(listDepth), schema(schema) { | 
|---|
| 686 | KJ_IREQUIRE(baseType != schema::Type::ANY_POINTER); | 
|---|
| 687 | } | 
|---|
| 688 |  | 
|---|
| 689 | void requireUsableAs(Type expected) const; | 
|---|
| 690 |  | 
|---|
| 691 | template <typename T, Kind k> | 
|---|
| 692 | struct FromValueImpl; | 
|---|
| 693 |  | 
|---|
| 694 | friend class ListSchema;  // only for requireUsableAs() | 
|---|
| 695 | }; | 
|---|
| 696 |  | 
|---|
| 697 | // ------------------------------------------------------------------- | 
|---|
| 698 |  | 
|---|
| 699 | class ListSchema { | 
|---|
| 700 | // ListSchema is a little different because list types are not described by schema nodes.  So, | 
|---|
| 701 | // ListSchema doesn't subclass Schema. | 
|---|
| 702 |  | 
|---|
| 703 | public: | 
|---|
| 704 | ListSchema() = default; | 
|---|
| 705 |  | 
|---|
| 706 | static ListSchema of(schema::Type::Which primitiveType); | 
|---|
| 707 | static ListSchema of(StructSchema elementType); | 
|---|
| 708 | static ListSchema of(EnumSchema elementType); | 
|---|
| 709 | static ListSchema of(InterfaceSchema elementType); | 
|---|
| 710 | static ListSchema of(ListSchema elementType); | 
|---|
| 711 | static ListSchema of(Type elementType); | 
|---|
| 712 | // Construct the schema for a list of the given type. | 
|---|
| 713 |  | 
|---|
| 714 | static ListSchema of(schema::Type::Reader elementType, Schema context) | 
|---|
| 715 | CAPNP_DEPRECATED( "Does not handle generics correctly."); | 
|---|
| 716 | // DEPRECATED: This method cannot correctly account for generic type parameter bindings that | 
|---|
| 717 | //   may apply to the input type. Instead of using this method, use a method of the Schema API | 
|---|
| 718 | //   that corresponds to the exact kind of dependency. For example, to get a field type, use | 
|---|
| 719 | //   StructSchema::Field::getType(). | 
|---|
| 720 | // | 
|---|
| 721 | // Construct from an element type schema.  Requires a context which can handle getDependency() | 
|---|
| 722 | // requests for any type ID found in the schema. | 
|---|
| 723 |  | 
|---|
| 724 | Type getElementType() const; | 
|---|
| 725 |  | 
|---|
| 726 | inline schema::Type::Which whichElementType() const; | 
|---|
| 727 | // Get the element type's "which()".  ListSchema does not actually store a schema::Type::Reader | 
|---|
| 728 | // describing the element type, but if it did, this would be equivalent to calling | 
|---|
| 729 | // .getBody().which() on that type. | 
|---|
| 730 |  | 
|---|
| 731 | StructSchema getStructElementType() const; | 
|---|
| 732 | EnumSchema getEnumElementType() const; | 
|---|
| 733 | InterfaceSchema getInterfaceElementType() const; | 
|---|
| 734 | ListSchema getListElementType() const; | 
|---|
| 735 | // Get the schema for complex element types.  Each of these throws an exception if the element | 
|---|
| 736 | // type is not of the requested kind. | 
|---|
| 737 |  | 
|---|
| 738 | inline bool operator==(const ListSchema& other) const { return elementType == other.elementType; } | 
|---|
| 739 | inline bool operator!=(const ListSchema& other) const { return elementType != other.elementType; } | 
|---|
| 740 |  | 
|---|
| 741 | template <typename T> | 
|---|
| 742 | void requireUsableAs() const; | 
|---|
| 743 |  | 
|---|
| 744 | private: | 
|---|
| 745 | Type elementType; | 
|---|
| 746 |  | 
|---|
| 747 | inline explicit ListSchema(Type elementType): elementType(elementType) {} | 
|---|
| 748 |  | 
|---|
| 749 | template <typename T> | 
|---|
| 750 | struct FromImpl; | 
|---|
| 751 | template <typename T> static inline ListSchema fromImpl() { | 
|---|
| 752 | return FromImpl<T>::get(); | 
|---|
| 753 | } | 
|---|
| 754 |  | 
|---|
| 755 | void requireUsableAs(ListSchema expected) const; | 
|---|
| 756 |  | 
|---|
| 757 | friend class Schema; | 
|---|
| 758 | }; | 
|---|
| 759 |  | 
|---|
| 760 | // ======================================================================================= | 
|---|
| 761 | // inline implementation | 
|---|
| 762 |  | 
|---|
| 763 | template <> inline schema::Type::Which Schema::from<Void>() { return schema::Type::VOID; } | 
|---|
| 764 | template <> inline schema::Type::Which Schema::from<bool>() { return schema::Type::BOOL; } | 
|---|
| 765 | template <> inline schema::Type::Which Schema::from<int8_t>() { return schema::Type::INT8; } | 
|---|
| 766 | template <> inline schema::Type::Which Schema::from<int16_t>() { return schema::Type::INT16; } | 
|---|
| 767 | template <> inline schema::Type::Which Schema::from<int32_t>() { return schema::Type::INT32; } | 
|---|
| 768 | template <> inline schema::Type::Which Schema::from<int64_t>() { return schema::Type::INT64; } | 
|---|
| 769 | template <> inline schema::Type::Which Schema::from<uint8_t>() { return schema::Type::UINT8; } | 
|---|
| 770 | template <> inline schema::Type::Which Schema::from<uint16_t>() { return schema::Type::UINT16; } | 
|---|
| 771 | template <> inline schema::Type::Which Schema::from<uint32_t>() { return schema::Type::UINT32; } | 
|---|
| 772 | template <> inline schema::Type::Which Schema::from<uint64_t>() { return schema::Type::UINT64; } | 
|---|
| 773 | template <> inline schema::Type::Which Schema::from<float>() { return schema::Type::FLOAT32; } | 
|---|
| 774 | template <> inline schema::Type::Which Schema::from<double>() { return schema::Type::FLOAT64; } | 
|---|
| 775 | template <> inline schema::Type::Which Schema::from<Text>() { return schema::Type::TEXT; } | 
|---|
| 776 | template <> inline schema::Type::Which Schema::from<Data>() { return schema::Type::DATA; } | 
|---|
| 777 |  | 
|---|
| 778 | inline Schema Schema::getDependency(uint64_t id) const { | 
|---|
| 779 | return getDependency(id, 0); | 
|---|
| 780 | } | 
|---|
| 781 |  | 
|---|
| 782 | inline bool Schema::isBranded() const { | 
|---|
| 783 | return raw != &raw->generic->defaultBrand; | 
|---|
| 784 | } | 
|---|
| 785 |  | 
|---|
| 786 | inline Schema Schema::getGeneric() const { | 
|---|
| 787 | return Schema(&raw->generic->defaultBrand); | 
|---|
| 788 | } | 
|---|
| 789 |  | 
|---|
| 790 | template <typename T> | 
|---|
| 791 | inline void Schema::requireUsableAs() const { | 
|---|
| 792 | requireUsableAs(&_::rawSchema<T>()); | 
|---|
| 793 | } | 
|---|
| 794 |  | 
|---|
| 795 | inline bool StructSchema::Field::operator==(const Field& other) const { | 
|---|
| 796 | return parent == other.parent && index == other.index; | 
|---|
| 797 | } | 
|---|
| 798 | inline bool EnumSchema::Enumerant::operator==(const Enumerant& other) const { | 
|---|
| 799 | return parent == other.parent && ordinal == other.ordinal; | 
|---|
| 800 | } | 
|---|
| 801 | inline bool InterfaceSchema::Method::operator==(const Method& other) const { | 
|---|
| 802 | return parent == other.parent && ordinal == other.ordinal; | 
|---|
| 803 | } | 
|---|
| 804 |  | 
|---|
| 805 | inline uint StructSchema::Field::hashCode() const { | 
|---|
| 806 | return kj::hashCode(parent, index); | 
|---|
| 807 | } | 
|---|
| 808 | inline uint EnumSchema::Enumerant::hashCode() const { | 
|---|
| 809 | return kj::hashCode(parent, ordinal); | 
|---|
| 810 | } | 
|---|
| 811 | inline uint InterfaceSchema::Method::hashCode() const { | 
|---|
| 812 | return kj::hashCode(parent, ordinal); | 
|---|
| 813 | } | 
|---|
| 814 |  | 
|---|
| 815 | inline ListSchema ListSchema::of(StructSchema elementType) { | 
|---|
| 816 | return ListSchema(Type(elementType)); | 
|---|
| 817 | } | 
|---|
| 818 | inline ListSchema ListSchema::of(EnumSchema elementType) { | 
|---|
| 819 | return ListSchema(Type(elementType)); | 
|---|
| 820 | } | 
|---|
| 821 | inline ListSchema ListSchema::of(InterfaceSchema elementType) { | 
|---|
| 822 | return ListSchema(Type(elementType)); | 
|---|
| 823 | } | 
|---|
| 824 | inline ListSchema ListSchema::of(ListSchema elementType) { | 
|---|
| 825 | return ListSchema(Type(elementType)); | 
|---|
| 826 | } | 
|---|
| 827 | inline ListSchema ListSchema::of(Type elementType) { | 
|---|
| 828 | return ListSchema(elementType); | 
|---|
| 829 | } | 
|---|
| 830 |  | 
|---|
| 831 | inline Type ListSchema::getElementType() const { | 
|---|
| 832 | return elementType; | 
|---|
| 833 | } | 
|---|
| 834 |  | 
|---|
| 835 | inline schema::Type::Which ListSchema::whichElementType() const { | 
|---|
| 836 | return elementType.which(); | 
|---|
| 837 | } | 
|---|
| 838 |  | 
|---|
| 839 | inline StructSchema ListSchema::getStructElementType() const { | 
|---|
| 840 | return elementType.asStruct(); | 
|---|
| 841 | } | 
|---|
| 842 |  | 
|---|
| 843 | inline EnumSchema ListSchema::getEnumElementType() const { | 
|---|
| 844 | return elementType.asEnum(); | 
|---|
| 845 | } | 
|---|
| 846 |  | 
|---|
| 847 | inline InterfaceSchema ListSchema::getInterfaceElementType() const { | 
|---|
| 848 | return elementType.asInterface(); | 
|---|
| 849 | } | 
|---|
| 850 |  | 
|---|
| 851 | inline ListSchema ListSchema::getListElementType() const { | 
|---|
| 852 | return elementType.asList(); | 
|---|
| 853 | } | 
|---|
| 854 |  | 
|---|
| 855 | template <typename T> | 
|---|
| 856 | inline void ListSchema::requireUsableAs() const { | 
|---|
| 857 | static_assert(kind<T>() == Kind::LIST, | 
|---|
| 858 | "ListSchema::requireUsableAs<T>() requires T is a list type."); | 
|---|
| 859 | requireUsableAs(Schema::from<T>()); | 
|---|
| 860 | } | 
|---|
| 861 |  | 
|---|
| 862 | inline void ListSchema::requireUsableAs(ListSchema expected) const { | 
|---|
| 863 | elementType.requireUsableAs(expected.elementType); | 
|---|
| 864 | } | 
|---|
| 865 |  | 
|---|
| 866 | template <typename T> | 
|---|
| 867 | struct ListSchema::FromImpl<List<T>> { | 
|---|
| 868 | static inline ListSchema get() { return of(Schema::from<T>()); } | 
|---|
| 869 | }; | 
|---|
| 870 |  | 
|---|
| 871 | inline Type::Type(): baseType(schema::Type::VOID), listDepth(0), schema(nullptr) {} | 
|---|
| 872 | inline Type::Type(schema::Type::Which primitive) | 
|---|
| 873 | : baseType(primitive), listDepth(0), isImplicitParam(false) { | 
|---|
| 874 | KJ_IREQUIRE(primitive != schema::Type::STRUCT && | 
|---|
| 875 | primitive != schema::Type::ENUM && | 
|---|
| 876 | primitive != schema::Type::INTERFACE && | 
|---|
| 877 | primitive != schema::Type::LIST); | 
|---|
| 878 | if (primitive == schema::Type::ANY_POINTER) { | 
|---|
| 879 | scopeId = 0; | 
|---|
| 880 | anyPointerKind = schema::Type::AnyPointer::Unconstrained::ANY_KIND; | 
|---|
| 881 | } else { | 
|---|
| 882 | schema = nullptr; | 
|---|
| 883 | } | 
|---|
| 884 | } | 
|---|
| 885 | inline Type::Type(schema::Type::Which derived, const _::RawBrandedSchema* schema) | 
|---|
| 886 | : baseType(derived), listDepth(0), isImplicitParam(false), schema(schema) { | 
|---|
| 887 | KJ_IREQUIRE(derived == schema::Type::STRUCT || | 
|---|
| 888 | derived == schema::Type::ENUM || | 
|---|
| 889 | derived == schema::Type::INTERFACE); | 
|---|
| 890 | } | 
|---|
| 891 |  | 
|---|
| 892 | inline Type::Type(StructSchema schema) | 
|---|
| 893 | : baseType(schema::Type::STRUCT), listDepth(0), schema(schema.raw) {} | 
|---|
| 894 | inline Type::Type(EnumSchema schema) | 
|---|
| 895 | : baseType(schema::Type::ENUM), listDepth(0), schema(schema.raw) {} | 
|---|
| 896 | inline Type::Type(InterfaceSchema schema) | 
|---|
| 897 | : baseType(schema::Type::INTERFACE), listDepth(0), schema(schema.raw) {} | 
|---|
| 898 | inline Type::Type(ListSchema schema) | 
|---|
| 899 | : Type(schema.getElementType()) { ++listDepth; } | 
|---|
| 900 | inline Type::Type(schema::Type::AnyPointer::Unconstrained::Which anyPointerKind) | 
|---|
| 901 | : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false), | 
|---|
| 902 | anyPointerKind(anyPointerKind), scopeId(0) {} | 
|---|
| 903 | inline Type::Type(BrandParameter param) | 
|---|
| 904 | : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(false), | 
|---|
| 905 | paramIndex(param.index), scopeId(param.scopeId) {} | 
|---|
| 906 | inline Type::Type(ImplicitParameter param) | 
|---|
| 907 | : baseType(schema::Type::ANY_POINTER), listDepth(0), isImplicitParam(true), | 
|---|
| 908 | paramIndex(param.index), scopeId(0) {} | 
|---|
| 909 |  | 
|---|
| 910 | inline schema::Type::Which Type::which() const { | 
|---|
| 911 | return listDepth > 0 ? schema::Type::LIST : baseType; | 
|---|
| 912 | } | 
|---|
| 913 |  | 
|---|
| 914 | inline schema::Type::AnyPointer::Unconstrained::Which Type::whichAnyPointerKind() const { | 
|---|
| 915 | KJ_IREQUIRE(baseType == schema::Type::ANY_POINTER); | 
|---|
| 916 | return !isImplicitParam && scopeId == 0 ? anyPointerKind | 
|---|
| 917 | : schema::Type::AnyPointer::Unconstrained::ANY_KIND; | 
|---|
| 918 | } | 
|---|
| 919 |  | 
|---|
| 920 | template <typename T> | 
|---|
| 921 | inline Type Type::from() { return Type(Schema::from<T>()); } | 
|---|
| 922 |  | 
|---|
| 923 | template <typename T, Kind k> | 
|---|
| 924 | struct Type::FromValueImpl { | 
|---|
| 925 | template <typename U> | 
|---|
| 926 | static inline Type type(U&& value) { | 
|---|
| 927 | return Type::from<T>(); | 
|---|
| 928 | } | 
|---|
| 929 | }; | 
|---|
| 930 |  | 
|---|
| 931 | template <typename T> | 
|---|
| 932 | struct Type::FromValueImpl<T, Kind::OTHER> { | 
|---|
| 933 | template <typename U> | 
|---|
| 934 | static inline Type type(U&& value) { | 
|---|
| 935 | // All dynamic types have getSchema(). | 
|---|
| 936 | return value.getSchema(); | 
|---|
| 937 | } | 
|---|
| 938 | }; | 
|---|
| 939 |  | 
|---|
| 940 | template <typename T> | 
|---|
| 941 | inline Type Type::from(T&& value) { | 
|---|
| 942 | typedef FromAny<kj::Decay<T>> Base; | 
|---|
| 943 | return Type::FromValueImpl<Base, kind<Base>()>::type(kj::fwd<T>(value)); | 
|---|
| 944 | } | 
|---|
| 945 |  | 
|---|
| 946 | inline bool Type::isVoid   () const { return baseType == schema::Type::VOID     && listDepth == 0; } | 
|---|
| 947 | inline bool Type::isBool   () const { return baseType == schema::Type::BOOL     && listDepth == 0; } | 
|---|
| 948 | inline bool Type::isInt8   () const { return baseType == schema::Type::INT8     && listDepth == 0; } | 
|---|
| 949 | inline bool Type::isInt16  () const { return baseType == schema::Type::INT16    && listDepth == 0; } | 
|---|
| 950 | inline bool Type::isInt32  () const { return baseType == schema::Type::INT32    && listDepth == 0; } | 
|---|
| 951 | inline bool Type::isInt64  () const { return baseType == schema::Type::INT64    && listDepth == 0; } | 
|---|
| 952 | inline bool Type::isUInt8  () const { return baseType == schema::Type::UINT8    && listDepth == 0; } | 
|---|
| 953 | inline bool Type::isUInt16 () const { return baseType == schema::Type::UINT16   && listDepth == 0; } | 
|---|
| 954 | inline bool Type::isUInt32 () const { return baseType == schema::Type::UINT32   && listDepth == 0; } | 
|---|
| 955 | inline bool Type::isUInt64 () const { return baseType == schema::Type::UINT64   && listDepth == 0; } | 
|---|
| 956 | inline bool Type::isFloat32() const { return baseType == schema::Type::FLOAT32  && listDepth == 0; } | 
|---|
| 957 | inline bool Type::isFloat64() const { return baseType == schema::Type::FLOAT64  && listDepth == 0; } | 
|---|
| 958 | inline bool Type::isText   () const { return baseType == schema::Type::TEXT     && listDepth == 0; } | 
|---|
| 959 | inline bool Type::isData   () const { return baseType == schema::Type::DATA     && listDepth == 0; } | 
|---|
| 960 | inline bool Type::isList   () const { return listDepth > 0; } | 
|---|
| 961 | inline bool Type::isEnum   () const { return baseType == schema::Type::ENUM     && listDepth == 0; } | 
|---|
| 962 | inline bool Type::isStruct () const { return baseType == schema::Type::STRUCT   && listDepth == 0; } | 
|---|
| 963 | inline bool Type::isInterface() const { | 
|---|
| 964 | return baseType == schema::Type::INTERFACE && listDepth == 0; | 
|---|
| 965 | } | 
|---|
| 966 | inline bool Type::isAnyPointer() const { | 
|---|
| 967 | return baseType == schema::Type::ANY_POINTER && listDepth == 0; | 
|---|
| 968 | } | 
|---|
| 969 |  | 
|---|
| 970 | inline Type Type::wrapInList(uint depth) const { | 
|---|
| 971 | Type result = *this; | 
|---|
| 972 | result.listDepth += depth; | 
|---|
| 973 | return result; | 
|---|
| 974 | } | 
|---|
| 975 |  | 
|---|
| 976 | }  // namespace capnp | 
|---|
| 977 |  | 
|---|