comparison osx/include/capnp/schema.h @ 49:3ab5a40c4e3b

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