Mercurial > hg > sv-dependency-builds
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_ |