comparison osx/include/capnp/dynamic.h @ 134:41e769c91eca

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
133:1ac99bfc383d 134:41e769c91eca
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 // This file defines classes that can be used to manipulate messages based on schemas that are not
23 // known until runtime. This is also useful for writing generic code that uses schemas to handle
24 // arbitrary types in a generic way.
25 //
26 // Each of the classes defined here has a to() template method which converts an instance back to a
27 // native type. This method will throw an exception if the requested type does not match the
28 // schema. To convert native types to dynamic, use DynamicFactory.
29 //
30 // As always, underlying data is validated lazily, so you have to actually traverse the whole
31 // message if you want to validate all content.
32
33 #ifndef CAPNP_DYNAMIC_H_
34 #define CAPNP_DYNAMIC_H_
35
36 #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS)
37 #pragma GCC system_header
38 #endif
39
40 #include "schema.h"
41 #include "layout.h"
42 #include "message.h"
43 #include "any.h"
44 #include "capability.h"
45
46 namespace capnp {
47
48 class MessageReader;
49 class MessageBuilder;
50
51 struct DynamicValue {
52 DynamicValue() = delete;
53
54 enum Type {
55 UNKNOWN,
56 // Means that the value has unknown type and content because it comes from a newer version of
57 // the schema, or from a newer version of Cap'n Proto that has new features that this version
58 // doesn't understand.
59
60 VOID,
61 BOOL,
62 INT,
63 UINT,
64 FLOAT,
65 TEXT,
66 DATA,
67 LIST,
68 ENUM,
69 STRUCT,
70 CAPABILITY,
71 ANY_POINTER
72 };
73
74 class Reader;
75 class Builder;
76 class Pipeline;
77 };
78 class DynamicEnum;
79 struct DynamicStruct {
80 DynamicStruct() = delete;
81 class Reader;
82 class Builder;
83 class Pipeline;
84 };
85 struct DynamicList {
86 DynamicList() = delete;
87 class Reader;
88 class Builder;
89 };
90 struct DynamicCapability {
91 DynamicCapability() = delete;
92 class Client;
93 class Server;
94 };
95 template <> class Orphan<DynamicValue>;
96
97 template <Kind k> struct DynamicTypeFor_;
98 template <> struct DynamicTypeFor_<Kind::ENUM> { typedef DynamicEnum Type; };
99 template <> struct DynamicTypeFor_<Kind::STRUCT> { typedef DynamicStruct Type; };
100 template <> struct DynamicTypeFor_<Kind::LIST> { typedef DynamicList Type; };
101 template <> struct DynamicTypeFor_<Kind::INTERFACE> { typedef DynamicCapability Type; };
102
103 template <typename T>
104 using DynamicTypeFor = typename DynamicTypeFor_<kind<T>()>::Type;
105
106 template <typename T>
107 ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value);
108 template <typename T>
109 BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value);
110 template <typename T>
111 DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
112 template <typename T>
113 typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value);
114
115 namespace _ { // private
116
117 template <> struct Kind_<DynamicValue > { static constexpr Kind kind = Kind::OTHER; };
118 template <> struct Kind_<DynamicEnum > { static constexpr Kind kind = Kind::OTHER; };
119 template <> struct Kind_<DynamicStruct > { static constexpr Kind kind = Kind::OTHER; };
120 template <> struct Kind_<DynamicList > { static constexpr Kind kind = Kind::OTHER; };
121 template <> struct Kind_<DynamicCapability> { static constexpr Kind kind = Kind::OTHER; };
122
123 } // namespace _ (private)
124
125 template <> inline constexpr Style style<DynamicValue >() { return Style::POINTER; }
126 template <> inline constexpr Style style<DynamicEnum >() { return Style::PRIMITIVE; }
127 template <> inline constexpr Style style<DynamicStruct >() { return Style::STRUCT; }
128 template <> inline constexpr Style style<DynamicList >() { return Style::POINTER; }
129 template <> inline constexpr Style style<DynamicCapability>() { return Style::CAPABILITY; }
130
131 // -------------------------------------------------------------------
132
133 class DynamicEnum {
134 public:
135 DynamicEnum() = default;
136 inline DynamicEnum(EnumSchema::Enumerant enumerant)
137 : schema(enumerant.getContainingEnum()), value(enumerant.getOrdinal()) {}
138 inline DynamicEnum(EnumSchema schema, uint16_t value)
139 : schema(schema), value(value) {}
140
141 template <typename T, typename = kj::EnableIf<kind<T>() == Kind::ENUM>>
142 inline DynamicEnum(T&& value): DynamicEnum(toDynamic(value)) {}
143
144 template <typename T>
145 inline T as() const { return static_cast<T>(asImpl(typeId<T>())); }
146 // Cast to a native enum type.
147
148 inline EnumSchema getSchema() const { return schema; }
149
150 kj::Maybe<EnumSchema::Enumerant> getEnumerant() const;
151 // Get which enumerant this enum value represents. Returns nullptr if the numeric value does not
152 // correspond to any enumerant in the schema -- this can happen if the data was built using a
153 // newer schema that has more values defined.
154
155 inline uint16_t getRaw() const { return value; }
156 // Returns the raw underlying enum value.
157
158 private:
159 EnumSchema schema;
160 uint16_t value;
161
162 uint16_t asImpl(uint64_t requestedTypeId) const;
163
164 friend struct DynamicStruct;
165 friend struct DynamicList;
166 friend struct DynamicValue;
167 template <typename T>
168 friend DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value);
169 };
170
171 // -------------------------------------------------------------------
172
173 class DynamicStruct::Reader {
174 public:
175 typedef DynamicStruct Reads;
176
177 Reader() = default;
178
179 template <typename T, typename = kj::EnableIf<kind<FromReader<T>>() == Kind::STRUCT>>
180 inline Reader(T&& value): Reader(toDynamic(value)) {}
181
182 inline MessageSize totalSize() const { return reader.totalSize().asPublic(); }
183
184 template <typename T>
185 typename T::Reader as() const;
186 // Convert the dynamic struct to its compiled-in type.
187
188 inline StructSchema getSchema() const { return schema; }
189
190 DynamicValue::Reader get(StructSchema::Field field) const;
191 // Read the given field value.
192
193 bool has(StructSchema::Field field) const;
194 // Tests whether the given field is set to its default value. For pointer values, this does
195 // not actually traverse the value comparing it with the default, but simply returns true if the
196 // pointer is non-null. For members of unions, has() returns false if the union member is not
197 // active, but does not necessarily return true if the member is active (depends on the field's
198 // value).
199
200 kj::Maybe<StructSchema::Field> which() const;
201 // If the struct contains an (unnamed) union, and the currently-active field within that union
202 // is known, this returns that field. Otherwise, it returns null. In other words, this returns
203 // null if there is no union present _or_ if the union's discriminant is set to an unrecognized
204 // value. This could happen in particular when receiving a message from a sender who has a
205 // newer version of the protocol and is using a field of the union that you don't know about yet.
206
207 DynamicValue::Reader get(kj::StringPtr name) const;
208 bool has(kj::StringPtr name) const;
209 // Shortcuts to access fields by name. These throw exceptions if no such field exists.
210
211 private:
212 StructSchema schema;
213 _::StructReader reader;
214
215 inline Reader(StructSchema schema, _::StructReader reader)
216 : schema(schema), reader(reader) {}
217
218 bool isSetInUnion(StructSchema::Field field) const;
219 void verifySetInUnion(StructSchema::Field field) const;
220 static DynamicValue::Reader getImpl(_::StructReader reader, StructSchema::Field field);
221
222 template <typename T, Kind K>
223 friend struct _::PointerHelpers;
224 friend class DynamicStruct::Builder;
225 friend struct DynamicList;
226 friend class MessageReader;
227 friend class MessageBuilder;
228 template <typename T, ::capnp::Kind k>
229 friend struct ::capnp::ToDynamic_;
230 friend kj::StringTree _::structString(
231 _::StructReader reader, const _::RawBrandedSchema& schema);
232 friend class Orphanage;
233 friend class Orphan<DynamicStruct>;
234 friend class Orphan<DynamicValue>;
235 friend class Orphan<AnyPointer>;
236 };
237
238 class DynamicStruct::Builder {
239 public:
240 typedef DynamicStruct Builds;
241
242 Builder() = default;
243 inline Builder(decltype(nullptr)) {}
244
245 template <typename T, typename = kj::EnableIf<kind<FromBuilder<T>>() == Kind::STRUCT>>
246 inline Builder(T&& value): Builder(toDynamic(value)) {}
247
248 inline MessageSize totalSize() const { return asReader().totalSize(); }
249
250 template <typename T>
251 typename T::Builder as();
252 // Cast to a particular struct type.
253
254 inline StructSchema getSchema() const { return schema; }
255
256 DynamicValue::Builder get(StructSchema::Field field);
257 // Read the given field value.
258
259 inline bool has(StructSchema::Field field) { return asReader().has(field); }
260 // Tests whether the given field is set to its default value. For pointer values, this does
261 // not actually traverse the value comparing it with the default, but simply returns true if the
262 // pointer is non-null. For members of unions, has() returns whether the field is currently
263 // active and the union as a whole is non-default -- so, the only time has() will return false
264 // for an active union field is if it is the default active field and it has its default value.
265
266 kj::Maybe<StructSchema::Field> which();
267 // If the struct contains an (unnamed) union, and the currently-active field within that union
268 // is known, this returns that field. Otherwise, it returns null. In other words, this returns
269 // null if there is no union present _or_ if the union's discriminant is set to an unrecognized
270 // value. This could happen in particular when receiving a message from a sender who has a
271 // newer version of the protocol and is using a field of the union that you don't know about yet.
272
273 void set(StructSchema::Field field, const DynamicValue::Reader& value);
274 // Set the given field value.
275
276 DynamicValue::Builder init(StructSchema::Field field);
277 DynamicValue::Builder init(StructSchema::Field field, uint size);
278 // Init a struct, list, or blob field.
279
280 void adopt(StructSchema::Field field, Orphan<DynamicValue>&& orphan);
281 Orphan<DynamicValue> disown(StructSchema::Field field);
282 // Adopt/disown. This works even for non-pointer fields: adopt() becomes equivalent to set()
283 // and disown() becomes like get() followed by clear().
284
285 void clear(StructSchema::Field field);
286 // Clear a field, setting it to its default value. For pointer fields, this actually makes the
287 // field null.
288
289 DynamicValue::Builder get(kj::StringPtr name);
290 bool has(kj::StringPtr name);
291 void set(kj::StringPtr name, const DynamicValue::Reader& value);
292 void set(kj::StringPtr name, std::initializer_list<DynamicValue::Reader> value);
293 DynamicValue::Builder init(kj::StringPtr name);
294 DynamicValue::Builder init(kj::StringPtr name, uint size);
295 void adopt(kj::StringPtr name, Orphan<DynamicValue>&& orphan);
296 Orphan<DynamicValue> disown(kj::StringPtr name);
297 void clear(kj::StringPtr name);
298 // Shortcuts to access fields by name. These throw exceptions if no such field exists.
299
300 Reader asReader() const;
301
302 private:
303 StructSchema schema;
304 _::StructBuilder builder;
305
306 inline Builder(StructSchema schema, _::StructBuilder builder)
307 : schema(schema), builder(builder) {}
308
309 bool isSetInUnion(StructSchema::Field field);
310 void verifySetInUnion(StructSchema::Field field);
311 void setInUnion(StructSchema::Field field);
312
313 template <typename T, Kind k>
314 friend struct _::PointerHelpers;
315 friend struct DynamicList;
316 friend class MessageReader;
317 friend class MessageBuilder;
318 template <typename T, ::capnp::Kind k>
319 friend struct ::capnp::ToDynamic_;
320 friend class Orphanage;
321 friend class Orphan<DynamicStruct>;
322 friend class Orphan<DynamicValue>;
323 friend class Orphan<AnyPointer>;
324 };
325
326 class DynamicStruct::Pipeline {
327 public:
328 typedef DynamicStruct Pipelines;
329
330 inline Pipeline(decltype(nullptr)): typeless(nullptr) {}
331
332 template <typename T>
333 typename T::Pipeline releaseAs();
334 // Convert the dynamic pipeline to its compiled-in type.
335
336 inline StructSchema getSchema() { return schema; }
337
338 DynamicValue::Pipeline get(StructSchema::Field field);
339 // Read the given field value.
340
341 DynamicValue::Pipeline get(kj::StringPtr name);
342 // Get by string name.
343
344 private:
345 StructSchema schema;
346 AnyPointer::Pipeline typeless;
347
348 inline explicit Pipeline(StructSchema schema, AnyPointer::Pipeline&& typeless)
349 : schema(schema), typeless(kj::mv(typeless)) {}
350
351 friend class Request<DynamicStruct, DynamicStruct>;
352 };
353
354 // -------------------------------------------------------------------
355
356 class DynamicList::Reader {
357 public:
358 typedef DynamicList Reads;
359
360 inline Reader(): reader(ElementSize::VOID) {}
361
362 template <typename T, typename = kj::EnableIf<kind<FromReader<T>>() == Kind::LIST>>
363 inline Reader(T&& value): Reader(toDynamic(value)) {}
364
365 template <typename T>
366 typename T::Reader as() const;
367 // Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
368 // can't possibly represent the requested type.
369
370 inline ListSchema getSchema() const { return schema; }
371
372 inline uint size() const { return reader.size() / ELEMENTS; }
373 DynamicValue::Reader operator[](uint index) const;
374
375 typedef _::IndexingIterator<const Reader, DynamicValue::Reader> Iterator;
376 inline Iterator begin() const { return Iterator(this, 0); }
377 inline Iterator end() const { return Iterator(this, size()); }
378
379 private:
380 ListSchema schema;
381 _::ListReader reader;
382
383 Reader(ListSchema schema, _::ListReader reader): schema(schema), reader(reader) {}
384
385 template <typename T, Kind k>
386 friend struct _::PointerHelpers;
387 friend struct DynamicStruct;
388 friend class DynamicList::Builder;
389 template <typename T, ::capnp::Kind k>
390 friend struct ::capnp::ToDynamic_;
391 friend class Orphanage;
392 friend class Orphan<DynamicList>;
393 friend class Orphan<DynamicValue>;
394 friend class Orphan<AnyPointer>;
395 };
396
397 class DynamicList::Builder {
398 public:
399 typedef DynamicList Builds;
400
401 inline Builder(): builder(ElementSize::VOID) {}
402 inline Builder(decltype(nullptr)): builder(ElementSize::VOID) {}
403
404 template <typename T, typename = kj::EnableIf<kind<FromBuilder<T>>() == Kind::LIST>>
405 inline Builder(T&& value): Builder(toDynamic(value)) {}
406
407 template <typename T>
408 typename T::Builder as();
409 // Try to convert to any List<T>, Data, or Text. Throws an exception if the underlying data
410 // can't possibly represent the requested type.
411
412 inline ListSchema getSchema() const { return schema; }
413
414 inline uint size() const { return builder.size() / ELEMENTS; }
415 DynamicValue::Builder operator[](uint index);
416 void set(uint index, const DynamicValue::Reader& value);
417 DynamicValue::Builder init(uint index, uint size);
418 void adopt(uint index, Orphan<DynamicValue>&& orphan);
419 Orphan<DynamicValue> disown(uint index);
420
421 typedef _::IndexingIterator<Builder, DynamicStruct::Builder> Iterator;
422 inline Iterator begin() { return Iterator(this, 0); }
423 inline Iterator end() { return Iterator(this, size()); }
424
425 void copyFrom(std::initializer_list<DynamicValue::Reader> value);
426
427 Reader asReader() const;
428
429 private:
430 ListSchema schema;
431 _::ListBuilder builder;
432
433 Builder(ListSchema schema, _::ListBuilder builder): schema(schema), builder(builder) {}
434
435 template <typename T, Kind k>
436 friend struct _::PointerHelpers;
437 friend struct DynamicStruct;
438 template <typename T, ::capnp::Kind k>
439 friend struct ::capnp::ToDynamic_;
440 friend class Orphanage;
441 template <typename T, Kind k>
442 friend struct _::OrphanGetImpl;
443 friend class Orphan<DynamicList>;
444 friend class Orphan<DynamicValue>;
445 friend class Orphan<AnyPointer>;
446 };
447
448 // -------------------------------------------------------------------
449
450 class DynamicCapability::Client: public Capability::Client {
451 public:
452 typedef DynamicCapability Calls;
453 typedef DynamicCapability Reads;
454
455 Client() = default;
456
457 template <typename T, typename = kj::EnableIf<kind<FromClient<T>>() == Kind::INTERFACE>>
458 inline Client(T&& client);
459
460 template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>>
461 inline Client(kj::Own<T>&& server);
462
463 template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
464 typename T::Client as();
465 template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
466 typename T::Client releaseAs();
467 // Convert to any client type.
468
469 Client upcast(InterfaceSchema requestedSchema);
470 // Upcast to a superclass. Throws an exception if `schema` is not a superclass.
471
472 inline InterfaceSchema getSchema() { return schema; }
473
474 Request<DynamicStruct, DynamicStruct> newRequest(
475 InterfaceSchema::Method method, kj::Maybe<MessageSize> sizeHint = nullptr);
476 Request<DynamicStruct, DynamicStruct> newRequest(
477 kj::StringPtr methodName, kj::Maybe<MessageSize> sizeHint = nullptr);
478
479 private:
480 InterfaceSchema schema;
481
482 Client(InterfaceSchema schema, kj::Own<ClientHook>&& hook)
483 : Capability::Client(kj::mv(hook)), schema(schema) {}
484
485 template <typename T>
486 inline Client(InterfaceSchema schema, kj::Own<T>&& server);
487
488 friend struct Capability;
489 friend struct DynamicStruct;
490 friend struct DynamicList;
491 friend struct DynamicValue;
492 friend class Orphan<DynamicCapability>;
493 friend class Orphan<DynamicValue>;
494 friend class Orphan<AnyPointer>;
495 template <typename T, Kind k>
496 friend struct _::PointerHelpers;
497 };
498
499 class DynamicCapability::Server: public Capability::Server {
500 public:
501 typedef DynamicCapability Serves;
502
503 Server(InterfaceSchema schema): schema(schema) {}
504
505 virtual kj::Promise<void> call(InterfaceSchema::Method method,
506 CallContext<DynamicStruct, DynamicStruct> context) = 0;
507
508 kj::Promise<void> dispatchCall(uint64_t interfaceId, uint16_t methodId,
509 CallContext<AnyPointer, AnyPointer> context) override final;
510
511 inline InterfaceSchema getSchema() const { return schema; }
512
513 private:
514 InterfaceSchema schema;
515 };
516
517 template <>
518 class Request<DynamicStruct, DynamicStruct>: public DynamicStruct::Builder {
519 // Specialization of `Request<T, U>` for DynamicStruct.
520
521 public:
522 inline Request(DynamicStruct::Builder builder, kj::Own<RequestHook>&& hook,
523 StructSchema resultSchema)
524 : DynamicStruct::Builder(builder), hook(kj::mv(hook)), resultSchema(resultSchema) {}
525
526 RemotePromise<DynamicStruct> send();
527 // Send the call and return a promise for the results.
528
529 private:
530 kj::Own<RequestHook> hook;
531 StructSchema resultSchema;
532
533 friend class Capability::Client;
534 friend struct DynamicCapability;
535 template <typename, typename>
536 friend class CallContext;
537 friend class RequestHook;
538 };
539
540 template <>
541 class CallContext<DynamicStruct, DynamicStruct>: public kj::DisallowConstCopy {
542 // Wrapper around CallContextHook with a specific return type.
543 //
544 // Methods of this class may only be called from within the server's event loop, not from other
545 // threads.
546
547 public:
548 explicit CallContext(CallContextHook& hook, StructSchema paramType, StructSchema resultType);
549
550 DynamicStruct::Reader getParams();
551 void releaseParams();
552 DynamicStruct::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr);
553 DynamicStruct::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr);
554 void setResults(DynamicStruct::Reader value);
555 void adoptResults(Orphan<DynamicStruct>&& value);
556 Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr);
557 template <typename SubParams>
558 kj::Promise<void> tailCall(Request<SubParams, DynamicStruct>&& tailRequest);
559 void allowCancellation();
560
561 private:
562 CallContextHook* hook;
563 StructSchema paramType;
564 StructSchema resultType;
565
566 friend class DynamicCapability::Server;
567 };
568
569 // -------------------------------------------------------------------
570
571 // Make sure ReaderFor<T> and BuilderFor<T> work for DynamicEnum, DynamicStruct, and
572 // DynamicList, so that we can define DynamicValue::as().
573
574 template <> struct ReaderFor_ <DynamicEnum, Kind::OTHER> { typedef DynamicEnum Type; };
575 template <> struct BuilderFor_<DynamicEnum, Kind::OTHER> { typedef DynamicEnum Type; };
576 template <> struct ReaderFor_ <DynamicStruct, Kind::OTHER> { typedef DynamicStruct::Reader Type; };
577 template <> struct BuilderFor_<DynamicStruct, Kind::OTHER> { typedef DynamicStruct::Builder Type; };
578 template <> struct ReaderFor_ <DynamicList, Kind::OTHER> { typedef DynamicList::Reader Type; };
579 template <> struct BuilderFor_<DynamicList, Kind::OTHER> { typedef DynamicList::Builder Type; };
580 template <> struct ReaderFor_ <DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; };
581 template <> struct BuilderFor_<DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; };
582 template <> struct PipelineFor_<DynamicCapability, Kind::OTHER> { typedef DynamicCapability::Client Type; };
583
584 class DynamicValue::Reader {
585 public:
586 typedef DynamicValue Reads;
587
588 inline Reader(decltype(nullptr) n = nullptr); // UNKNOWN
589 inline Reader(Void value);
590 inline Reader(bool value);
591 inline Reader(char value);
592 inline Reader(signed char value);
593 inline Reader(short value);
594 inline Reader(int value);
595 inline Reader(long value);
596 inline Reader(long long value);
597 inline Reader(unsigned char value);
598 inline Reader(unsigned short value);
599 inline Reader(unsigned int value);
600 inline Reader(unsigned long value);
601 inline Reader(unsigned long long value);
602 inline Reader(float value);
603 inline Reader(double value);
604 inline Reader(const char* value); // Text
605 inline Reader(const Text::Reader& value);
606 inline Reader(const Data::Reader& value);
607 inline Reader(const DynamicList::Reader& value);
608 inline Reader(DynamicEnum value);
609 inline Reader(const DynamicStruct::Reader& value);
610 inline Reader(const AnyPointer::Reader& value);
611 inline Reader(DynamicCapability::Client& value);
612 inline Reader(DynamicCapability::Client&& value);
613 template <typename T, typename = kj::EnableIf<kj::canConvert<T*, DynamicCapability::Server*>()>>
614 inline Reader(kj::Own<T>&& value);
615 Reader(ConstSchema constant);
616
617 template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
618 inline Reader(T&& value): Reader(toDynamic(kj::mv(value))) {}
619
620 Reader(const Reader& other);
621 Reader(Reader&& other) noexcept;
622 ~Reader() noexcept(false);
623 Reader& operator=(const Reader& other);
624 Reader& operator=(Reader&& other);
625 // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not
626 // trivially copyable.
627
628 template <typename T>
629 inline ReaderFor<T> as() const { return AsImpl<T>::apply(*this); }
630 // Use to interpret the value as some Cap'n Proto type. Allowed types are:
631 // - Void, bool, [u]int{8,16,32,64}_t, float, double, any enum: Returns the raw value.
632 // - Text, Data, AnyPointer, any struct type: Returns the corresponding Reader.
633 // - List<T> for any T listed above: Returns List<T>::Reader.
634 // - DynamicEnum: Returns the corresponding type.
635 // - DynamicStruct, DynamicList: Returns the corresponding Reader.
636 // - Any capability type, including DynamicCapability: Returns the corresponding Client.
637 // (TODO(perf): On GCC 4.8 / Clang 3.3, provide rvalue-qualified version that avoids
638 // refcounting.)
639 //
640 // DynamicValue allows various implicit conversions, mostly just to make the interface friendlier.
641 // - Any integer can be converted to any other integer type so long as the actual value is within
642 // the new type's range.
643 // - Floating-point types can be converted to integers as long as no information would be lost
644 // in the conversion.
645 // - Integers can be converted to floating points. This may lose information, but won't throw.
646 // - Float32/Float64 can be converted between each other. Converting Float64 -> Float32 may lose
647 // information, but won't throw.
648 // - Text can be converted to an enum, if the Text matches one of the enumerant names (but not
649 // vice-versa).
650 // - Capabilities can be upcast (cast to a supertype), but not downcast.
651 //
652 // Any other conversion attempt will throw an exception.
653
654 inline Type getType() const { return type; }
655 // Get the type of this value.
656
657 private:
658 Type type;
659
660 union {
661 Void voidValue;
662 bool boolValue;
663 int64_t intValue;
664 uint64_t uintValue;
665 double floatValue;
666 Text::Reader textValue;
667 Data::Reader dataValue;
668 DynamicList::Reader listValue;
669 DynamicEnum enumValue;
670 DynamicStruct::Reader structValue;
671 AnyPointer::Reader anyPointerValue;
672
673 mutable DynamicCapability::Client capabilityValue;
674 // Declared mutable because `Client`s normally cannot be const.
675
676 // Warning: Copy/move constructors assume all these types are trivially copyable except
677 // Capability.
678 };
679
680 template <typename T, Kind kind = kind<T>()> struct AsImpl;
681 // Implementation backing the as() method. Needs to be a struct to allow partial
682 // specialization. Has a method apply() which does the work.
683
684 friend class Orphanage; // to speed up newOrphanCopy(DynamicValue::Reader)
685 };
686
687 class DynamicValue::Builder {
688 public:
689 typedef DynamicValue Builds;
690
691 inline Builder(decltype(nullptr) n = nullptr); // UNKNOWN
692 inline Builder(Void value);
693 inline Builder(bool value);
694 inline Builder(char value);
695 inline Builder(signed char value);
696 inline Builder(short value);
697 inline Builder(int value);
698 inline Builder(long value);
699 inline Builder(long long value);
700 inline Builder(unsigned char value);
701 inline Builder(unsigned short value);
702 inline Builder(unsigned int value);
703 inline Builder(unsigned long value);
704 inline Builder(unsigned long long value);
705 inline Builder(float value);
706 inline Builder(double value);
707 inline Builder(Text::Builder value);
708 inline Builder(Data::Builder value);
709 inline Builder(DynamicList::Builder value);
710 inline Builder(DynamicEnum value);
711 inline Builder(DynamicStruct::Builder value);
712 inline Builder(AnyPointer::Builder value);
713 inline Builder(DynamicCapability::Client& value);
714 inline Builder(DynamicCapability::Client&& value);
715
716 template <typename T, typename = decltype(toDynamic(kj::instance<T>()))>
717 inline Builder(T value): Builder(toDynamic(value)) {}
718
719 Builder(Builder& other);
720 Builder(Builder&& other) noexcept;
721 ~Builder() noexcept(false);
722 Builder& operator=(Builder& other);
723 Builder& operator=(Builder&& other);
724 // Unfortunately, we cannot use the implicit definitions of these since DynamicCapability is not
725 // trivially copyable.
726
727 template <typename T>
728 inline BuilderFor<T> as() { return AsImpl<T>::apply(*this); }
729 // See DynamicValue::Reader::as().
730
731 inline Type getType() { return type; }
732 // Get the type of this value.
733
734 Reader asReader() const;
735
736 private:
737 Type type;
738
739 union {
740 Void voidValue;
741 bool boolValue;
742 int64_t intValue;
743 uint64_t uintValue;
744 double floatValue;
745 Text::Builder textValue;
746 Data::Builder dataValue;
747 DynamicList::Builder listValue;
748 DynamicEnum enumValue;
749 DynamicStruct::Builder structValue;
750 AnyPointer::Builder anyPointerValue;
751
752 mutable DynamicCapability::Client capabilityValue;
753 // Declared mutable because `Client`s normally cannot be const.
754 };
755
756 template <typename T, Kind kind = kind<T>()> struct AsImpl;
757 // Implementation backing the as() method. Needs to be a struct to allow partial
758 // specialization. Has a method apply() which does the work.
759
760 friend class Orphan<DynamicValue>;
761 };
762
763 class DynamicValue::Pipeline {
764 public:
765 typedef DynamicValue Pipelines;
766
767 inline Pipeline(decltype(nullptr) n = nullptr);
768 inline Pipeline(DynamicStruct::Pipeline&& value);
769 inline Pipeline(DynamicCapability::Client&& value);
770
771 Pipeline(Pipeline&& other) noexcept;
772 Pipeline& operator=(Pipeline&& other);
773 ~Pipeline() noexcept(false);
774
775 template <typename T>
776 inline PipelineFor<T> releaseAs() { return AsImpl<T>::apply(*this); }
777
778 inline Type getType() { return type; }
779 // Get the type of this value.
780
781 private:
782 Type type;
783 union {
784 DynamicStruct::Pipeline structValue;
785 DynamicCapability::Client capabilityValue;
786 };
787
788 template <typename T, Kind kind = kind<T>()> struct AsImpl;
789 // Implementation backing the releaseAs() method. Needs to be a struct to allow partial
790 // specialization. Has a method apply() which does the work.
791 };
792
793 kj::StringTree KJ_STRINGIFY(const DynamicValue::Reader& value);
794 kj::StringTree KJ_STRINGIFY(const DynamicValue::Builder& value);
795 kj::StringTree KJ_STRINGIFY(DynamicEnum value);
796 kj::StringTree KJ_STRINGIFY(const DynamicStruct::Reader& value);
797 kj::StringTree KJ_STRINGIFY(const DynamicStruct::Builder& value);
798 kj::StringTree KJ_STRINGIFY(const DynamicList::Reader& value);
799 kj::StringTree KJ_STRINGIFY(const DynamicList::Builder& value);
800
801 // -------------------------------------------------------------------
802 // Orphan <-> Dynamic glue
803
804 template <>
805 class Orphan<DynamicStruct> {
806 public:
807 Orphan() = default;
808 KJ_DISALLOW_COPY(Orphan);
809 Orphan(Orphan&&) = default;
810 Orphan& operator=(Orphan&&) = default;
811
812 template <typename T, typename = kj::EnableIf<kind<T>() == Kind::STRUCT>>
813 inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {}
814
815 DynamicStruct::Builder get();
816 DynamicStruct::Reader getReader() const;
817
818 template <typename T>
819 Orphan<T> releaseAs();
820 // Like DynamicStruct::Builder::as(), but coerces the Orphan type. Since Orphans are move-only,
821 // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
822 // transferred to the returned Orphan<T>.
823
824 inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
825 inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
826
827 private:
828 StructSchema schema;
829 _::OrphanBuilder builder;
830
831 inline Orphan(StructSchema schema, _::OrphanBuilder&& builder)
832 : schema(schema), builder(kj::mv(builder)) {}
833
834 template <typename, Kind>
835 friend struct _::PointerHelpers;
836 friend struct DynamicList;
837 friend class Orphanage;
838 friend class Orphan<DynamicValue>;
839 friend class Orphan<AnyPointer>;
840 friend class MessageBuilder;
841 };
842
843 template <>
844 class Orphan<DynamicList> {
845 public:
846 Orphan() = default;
847 KJ_DISALLOW_COPY(Orphan);
848 Orphan(Orphan&&) = default;
849 Orphan& operator=(Orphan&&) = default;
850
851 template <typename T, typename = kj::EnableIf<kind<T>() == Kind::LIST>>
852 inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {}
853
854 DynamicList::Builder get();
855 DynamicList::Reader getReader() const;
856
857 template <typename T>
858 Orphan<T> releaseAs();
859 // Like DynamicList::Builder::as(), but coerces the Orphan type. Since Orphans are move-only,
860 // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
861 // transferred to the returned Orphan<T>.
862
863 // TODO(someday): Support truncate().
864
865 inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
866 inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
867
868 private:
869 ListSchema schema;
870 _::OrphanBuilder builder;
871
872 inline Orphan(ListSchema schema, _::OrphanBuilder&& builder)
873 : schema(schema), builder(kj::mv(builder)) {}
874
875 template <typename, Kind>
876 friend struct _::PointerHelpers;
877 friend struct DynamicList;
878 friend class Orphanage;
879 friend class Orphan<DynamicValue>;
880 friend class Orphan<AnyPointer>;
881 };
882
883 template <>
884 class Orphan<DynamicCapability> {
885 public:
886 Orphan() = default;
887 KJ_DISALLOW_COPY(Orphan);
888 Orphan(Orphan&&) = default;
889 Orphan& operator=(Orphan&&) = default;
890
891 template <typename T, typename = kj::EnableIf<kind<T>() == Kind::INTERFACE>>
892 inline Orphan(Orphan<T>&& other): schema(Schema::from<T>()), builder(kj::mv(other.builder)) {}
893
894 DynamicCapability::Client get();
895 DynamicCapability::Client getReader() const;
896
897 template <typename T>
898 Orphan<T> releaseAs();
899 // Like DynamicCapability::Client::as(), but coerces the Orphan type. Since Orphans are move-only,
900 // the original Orphan<DynamicCapability> is no longer valid after this call; ownership is
901 // transferred to the returned Orphan<T>.
902
903 inline bool operator==(decltype(nullptr)) const { return builder == nullptr; }
904 inline bool operator!=(decltype(nullptr)) const { return builder != nullptr; }
905
906 private:
907 InterfaceSchema schema;
908 _::OrphanBuilder builder;
909
910 inline Orphan(InterfaceSchema schema, _::OrphanBuilder&& builder)
911 : schema(schema), builder(kj::mv(builder)) {}
912
913 template <typename, Kind>
914 friend struct _::PointerHelpers;
915 friend struct DynamicList;
916 friend class Orphanage;
917 friend class Orphan<DynamicValue>;
918 friend class Orphan<AnyPointer>;
919 };
920
921 template <>
922 class Orphan<DynamicValue> {
923 public:
924 inline Orphan(decltype(nullptr) n = nullptr): type(DynamicValue::UNKNOWN) {}
925 inline Orphan(Void value);
926 inline Orphan(bool value);
927 inline Orphan(char value);
928 inline Orphan(signed char value);
929 inline Orphan(short value);
930 inline Orphan(int value);
931 inline Orphan(long value);
932 inline Orphan(long long value);
933 inline Orphan(unsigned char value);
934 inline Orphan(unsigned short value);
935 inline Orphan(unsigned int value);
936 inline Orphan(unsigned long value);
937 inline Orphan(unsigned long long value);
938 inline Orphan(float value);
939 inline Orphan(double value);
940 inline Orphan(DynamicEnum value);
941 Orphan(Orphan&&) = default;
942 template <typename T>
943 Orphan(Orphan<T>&&);
944 Orphan(Orphan<AnyPointer>&&);
945 Orphan(void*) = delete; // So Orphan(bool) doesn't accept pointers.
946 KJ_DISALLOW_COPY(Orphan);
947
948 Orphan& operator=(Orphan&&) = default;
949
950 inline DynamicValue::Type getType() { return type; }
951
952 DynamicValue::Builder get();
953 DynamicValue::Reader getReader() const;
954
955 template <typename T>
956 Orphan<T> releaseAs();
957 // Like DynamicValue::Builder::as(), but coerces the Orphan type. Since Orphans are move-only,
958 // the original Orphan<DynamicStruct> is no longer valid after this call; ownership is
959 // transferred to the returned Orphan<T>.
960
961 private:
962 DynamicValue::Type type;
963 union {
964 Void voidValue;
965 bool boolValue;
966 int64_t intValue;
967 uint64_t uintValue;
968 double floatValue;
969 DynamicEnum enumValue;
970 StructSchema structSchema;
971 ListSchema listSchema;
972 InterfaceSchema interfaceSchema;
973 };
974
975 _::OrphanBuilder builder;
976 // Only used if `type` is a pointer type.
977
978 Orphan(DynamicValue::Builder value, _::OrphanBuilder&& builder);
979 Orphan(DynamicValue::Type type, _::OrphanBuilder&& builder)
980 : type(type), builder(kj::mv(builder)) {}
981 Orphan(StructSchema structSchema, _::OrphanBuilder&& builder)
982 : type(DynamicValue::STRUCT), structSchema(structSchema), builder(kj::mv(builder)) {}
983 Orphan(ListSchema listSchema, _::OrphanBuilder&& builder)
984 : type(DynamicValue::LIST), listSchema(listSchema), builder(kj::mv(builder)) {}
985
986 template <typename, Kind>
987 friend struct _::PointerHelpers;
988 friend struct DynamicStruct;
989 friend struct DynamicList;
990 friend struct AnyPointer;
991 friend class Orphanage;
992 };
993
994 template <typename T>
995 inline Orphan<DynamicValue>::Orphan(Orphan<T>&& other)
996 : Orphan(other.get(), kj::mv(other.builder)) {}
997
998 inline Orphan<DynamicValue>::Orphan(Orphan<AnyPointer>&& other)
999 : type(DynamicValue::ANY_POINTER), builder(kj::mv(other.builder)) {}
1000
1001 template <typename T>
1002 Orphan<T> Orphan<DynamicStruct>::releaseAs() {
1003 get().as<T>(); // type check
1004 return Orphan<T>(kj::mv(builder));
1005 }
1006
1007 template <typename T>
1008 Orphan<T> Orphan<DynamicList>::releaseAs() {
1009 get().as<T>(); // type check
1010 return Orphan<T>(kj::mv(builder));
1011 }
1012
1013 template <typename T>
1014 Orphan<T> Orphan<DynamicCapability>::releaseAs() {
1015 get().as<T>(); // type check
1016 return Orphan<T>(kj::mv(builder));
1017 }
1018
1019 template <typename T>
1020 Orphan<T> Orphan<DynamicValue>::releaseAs() {
1021 get().as<T>(); // type check
1022 type = DynamicValue::UNKNOWN;
1023 return Orphan<T>(kj::mv(builder));
1024 }
1025
1026 template <>
1027 Orphan<AnyPointer> Orphan<DynamicValue>::releaseAs<AnyPointer>();
1028 template <>
1029 Orphan<DynamicStruct> Orphan<DynamicValue>::releaseAs<DynamicStruct>();
1030 template <>
1031 Orphan<DynamicList> Orphan<DynamicValue>::releaseAs<DynamicList>();
1032 template <>
1033 Orphan<DynamicCapability> Orphan<DynamicValue>::releaseAs<DynamicCapability>();
1034
1035 template <>
1036 struct Orphanage::GetInnerBuilder<DynamicStruct, Kind::OTHER> {
1037 static inline _::StructBuilder apply(DynamicStruct::Builder& t) {
1038 return t.builder;
1039 }
1040 };
1041
1042 template <>
1043 struct Orphanage::GetInnerBuilder<DynamicList, Kind::OTHER> {
1044 static inline _::ListBuilder apply(DynamicList::Builder& t) {
1045 return t.builder;
1046 }
1047 };
1048
1049 template <>
1050 inline Orphan<DynamicStruct> Orphanage::newOrphanCopy<DynamicStruct::Reader>(
1051 DynamicStruct::Reader copyFrom) const {
1052 return Orphan<DynamicStruct>(
1053 copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1054 }
1055
1056 template <>
1057 inline Orphan<DynamicList> Orphanage::newOrphanCopy<DynamicList::Reader>(
1058 DynamicList::Reader copyFrom) const {
1059 return Orphan<DynamicList>(copyFrom.getSchema(),
1060 _::OrphanBuilder::copy(arena, capTable, copyFrom.reader));
1061 }
1062
1063 template <>
1064 inline Orphan<DynamicCapability> Orphanage::newOrphanCopy<DynamicCapability::Client>(
1065 DynamicCapability::Client copyFrom) const {
1066 return Orphan<DynamicCapability>(
1067 copyFrom.getSchema(), _::OrphanBuilder::copy(arena, capTable, copyFrom.hook->addRef()));
1068 }
1069
1070 template <>
1071 Orphan<DynamicValue> Orphanage::newOrphanCopy<DynamicValue::Reader>(
1072 DynamicValue::Reader copyFrom) const;
1073
1074 namespace _ { // private
1075
1076 template <>
1077 struct PointerHelpers<DynamicStruct, Kind::OTHER> {
1078 // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1079 // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we
1080 // don't want people to accidentally be able to provide their own default value.
1081 static DynamicStruct::Reader getDynamic(PointerReader reader, StructSchema schema);
1082 static DynamicStruct::Builder getDynamic(PointerBuilder builder, StructSchema schema);
1083 static void set(PointerBuilder builder, const DynamicStruct::Reader& value);
1084 static DynamicStruct::Builder init(PointerBuilder builder, StructSchema schema);
1085 static inline void adopt(PointerBuilder builder, Orphan<DynamicStruct>&& value) {
1086 builder.adopt(kj::mv(value.builder));
1087 }
1088 static inline Orphan<DynamicStruct> disown(PointerBuilder builder, StructSchema schema) {
1089 return Orphan<DynamicStruct>(schema, builder.disown());
1090 }
1091 };
1092
1093 template <>
1094 struct PointerHelpers<DynamicList, Kind::OTHER> {
1095 // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1096 // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we
1097 // don't want people to accidentally be able to provide their own default value.
1098 static DynamicList::Reader getDynamic(PointerReader reader, ListSchema schema);
1099 static DynamicList::Builder getDynamic(PointerBuilder builder, ListSchema schema);
1100 static void set(PointerBuilder builder, const DynamicList::Reader& value);
1101 static DynamicList::Builder init(PointerBuilder builder, ListSchema schema, uint size);
1102 static inline void adopt(PointerBuilder builder, Orphan<DynamicList>&& value) {
1103 builder.adopt(kj::mv(value.builder));
1104 }
1105 static inline Orphan<DynamicList> disown(PointerBuilder builder, ListSchema schema) {
1106 return Orphan<DynamicList>(schema, builder.disown());
1107 }
1108 };
1109
1110 template <>
1111 struct PointerHelpers<DynamicCapability, Kind::OTHER> {
1112 // getDynamic() is used when an AnyPointer's get() accessor is passed arguments, because for
1113 // non-dynamic types PointerHelpers::get() takes a default value as the third argument, and we
1114 // don't want people to accidentally be able to provide their own default value.
1115 static DynamicCapability::Client getDynamic(PointerReader reader, InterfaceSchema schema);
1116 static DynamicCapability::Client getDynamic(PointerBuilder builder, InterfaceSchema schema);
1117 static void set(PointerBuilder builder, DynamicCapability::Client& value);
1118 static void set(PointerBuilder builder, DynamicCapability::Client&& value);
1119 static inline void adopt(PointerBuilder builder, Orphan<DynamicCapability>&& value) {
1120 builder.adopt(kj::mv(value.builder));
1121 }
1122 static inline Orphan<DynamicCapability> disown(PointerBuilder builder, InterfaceSchema schema) {
1123 return Orphan<DynamicCapability>(schema, builder.disown());
1124 }
1125 };
1126
1127 } // namespace _ (private)
1128
1129 template <typename T>
1130 inline ReaderFor<T> AnyPointer::Reader::getAs(StructSchema schema) const {
1131 return _::PointerHelpers<T>::getDynamic(reader, schema);
1132 }
1133 template <typename T>
1134 inline ReaderFor<T> AnyPointer::Reader::getAs(ListSchema schema) const {
1135 return _::PointerHelpers<T>::getDynamic(reader, schema);
1136 }
1137 template <typename T>
1138 inline ReaderFor<T> AnyPointer::Reader::getAs(InterfaceSchema schema) const {
1139 return _::PointerHelpers<T>::getDynamic(reader, schema);
1140 }
1141 template <typename T>
1142 inline BuilderFor<T> AnyPointer::Builder::getAs(StructSchema schema) {
1143 return _::PointerHelpers<T>::getDynamic(builder, schema);
1144 }
1145 template <typename T>
1146 inline BuilderFor<T> AnyPointer::Builder::getAs(ListSchema schema) {
1147 return _::PointerHelpers<T>::getDynamic(builder, schema);
1148 }
1149 template <typename T>
1150 inline BuilderFor<T> AnyPointer::Builder::getAs(InterfaceSchema schema) {
1151 return _::PointerHelpers<T>::getDynamic(builder, schema);
1152 }
1153 template <typename T>
1154 inline BuilderFor<T> AnyPointer::Builder::initAs(StructSchema schema) {
1155 return _::PointerHelpers<T>::init(builder, schema);
1156 }
1157 template <typename T>
1158 inline BuilderFor<T> AnyPointer::Builder::initAs(ListSchema schema, uint elementCount) {
1159 return _::PointerHelpers<T>::init(builder, schema, elementCount);
1160 }
1161 template <>
1162 inline void AnyPointer::Builder::setAs<DynamicStruct>(DynamicStruct::Reader value) {
1163 return _::PointerHelpers<DynamicStruct>::set(builder, value);
1164 }
1165 template <>
1166 inline void AnyPointer::Builder::setAs<DynamicList>(DynamicList::Reader value) {
1167 return _::PointerHelpers<DynamicList>::set(builder, value);
1168 }
1169 template <>
1170 inline void AnyPointer::Builder::setAs<DynamicCapability>(DynamicCapability::Client value) {
1171 return _::PointerHelpers<DynamicCapability>::set(builder, kj::mv(value));
1172 }
1173 template <>
1174 void AnyPointer::Builder::adopt<DynamicValue>(Orphan<DynamicValue>&& orphan);
1175 template <typename T>
1176 inline Orphan<T> AnyPointer::Builder::disownAs(StructSchema schema) {
1177 return _::PointerHelpers<T>::disown(builder, schema);
1178 }
1179 template <typename T>
1180 inline Orphan<T> AnyPointer::Builder::disownAs(ListSchema schema) {
1181 return _::PointerHelpers<T>::disown(builder, schema);
1182 }
1183 template <typename T>
1184 inline Orphan<T> AnyPointer::Builder::disownAs(InterfaceSchema schema) {
1185 return _::PointerHelpers<T>::disown(builder, schema);
1186 }
1187
1188 template <>
1189 DynamicStruct::Builder Orphan<AnyPointer>::getAs<DynamicStruct>(StructSchema schema);
1190 template <>
1191 DynamicList::Builder Orphan<AnyPointer>::getAs<DynamicList>(ListSchema schema);
1192 template <>
1193 DynamicCapability::Client Orphan<AnyPointer>::getAs<DynamicCapability>(InterfaceSchema schema);
1194 template <>
1195 DynamicStruct::Reader Orphan<AnyPointer>::getAsReader<DynamicStruct>(StructSchema schema) const;
1196 template <>
1197 DynamicList::Reader Orphan<AnyPointer>::getAsReader<DynamicList>(ListSchema schema) const;
1198 template <>
1199 DynamicCapability::Client Orphan<AnyPointer>::getAsReader<DynamicCapability>(
1200 InterfaceSchema schema) const;
1201 template <>
1202 Orphan<DynamicStruct> Orphan<AnyPointer>::releaseAs<DynamicStruct>(StructSchema schema);
1203 template <>
1204 Orphan<DynamicList> Orphan<AnyPointer>::releaseAs<DynamicList>(ListSchema schema);
1205 template <>
1206 Orphan<DynamicCapability> Orphan<AnyPointer>::releaseAs<DynamicCapability>(
1207 InterfaceSchema schema);
1208
1209 // =======================================================================================
1210 // Inline implementation details.
1211
1212 template <typename T>
1213 struct ToDynamic_<T, Kind::STRUCT> {
1214 static inline DynamicStruct::Reader apply(const typename T::Reader& value) {
1215 return DynamicStruct::Reader(Schema::from<T>(), value._reader);
1216 }
1217 static inline DynamicStruct::Builder apply(typename T::Builder& value) {
1218 return DynamicStruct::Builder(Schema::from<T>(), value._builder);
1219 }
1220 };
1221
1222 template <typename T>
1223 struct ToDynamic_<T, Kind::LIST> {
1224 static inline DynamicList::Reader apply(const typename T::Reader& value) {
1225 return DynamicList::Reader(Schema::from<T>(), value.reader);
1226 }
1227 static inline DynamicList::Builder apply(typename T::Builder& value) {
1228 return DynamicList::Builder(Schema::from<T>(), value.builder);
1229 }
1230 };
1231
1232 template <typename T>
1233 struct ToDynamic_<T, Kind::INTERFACE> {
1234 static inline DynamicCapability::Client apply(typename T::Client value) {
1235 return DynamicCapability::Client(kj::mv(value));
1236 }
1237 static inline DynamicCapability::Client apply(typename T::Client&& value) {
1238 return DynamicCapability::Client(kj::mv(value));
1239 }
1240 };
1241
1242 template <typename T>
1243 ReaderFor<DynamicTypeFor<FromReader<T>>> toDynamic(T&& value) {
1244 return ToDynamic_<FromReader<T>>::apply(value);
1245 }
1246 template <typename T>
1247 BuilderFor<DynamicTypeFor<FromBuilder<T>>> toDynamic(T&& value) {
1248 return ToDynamic_<FromBuilder<T>>::apply(value);
1249 }
1250 template <typename T>
1251 DynamicTypeFor<TypeIfEnum<T>> toDynamic(T&& value) {
1252 return DynamicEnum(Schema::from<kj::Decay<T>>(), static_cast<uint16_t>(value));
1253 }
1254 template <typename T>
1255 typename DynamicTypeFor<FromServer<T>>::Client toDynamic(kj::Own<T>&& value) {
1256 return typename FromServer<T>::Client(kj::mv(value));
1257 }
1258
1259 inline DynamicValue::Reader::Reader(std::nullptr_t n): type(UNKNOWN) {}
1260 inline DynamicValue::Builder::Builder(std::nullptr_t n): type(UNKNOWN) {}
1261
1262 #define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1263 inline DynamicValue::Reader::Reader(cppType value) \
1264 : type(typeTag), fieldName##Value(value) {} \
1265 inline DynamicValue::Builder::Builder(cppType value) \
1266 : type(typeTag), fieldName##Value(value) {} \
1267 inline Orphan<DynamicValue>::Orphan(cppType value) \
1268 : type(DynamicValue::typeTag), fieldName##Value(value) {}
1269
1270 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Void, VOID, void);
1271 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(bool, BOOL, bool);
1272 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(char, INT, int);
1273 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(signed char, INT, int);
1274 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(short, INT, int);
1275 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(int, INT, int);
1276 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long, INT, int);
1277 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(long long, INT, int);
1278 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned char, UINT, uint);
1279 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned short, UINT, uint);
1280 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned int, UINT, uint);
1281 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long, UINT, uint);
1282 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(unsigned long long, UINT, uint);
1283 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(float, FLOAT, float);
1284 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(double, FLOAT, float);
1285 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicEnum, ENUM, enum);
1286 #undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
1287
1288 #define CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(cppType, typeTag, fieldName) \
1289 inline DynamicValue::Reader::Reader(const cppType::Reader& value) \
1290 : type(typeTag), fieldName##Value(value) {} \
1291 inline DynamicValue::Builder::Builder(cppType::Builder value) \
1292 : type(typeTag), fieldName##Value(value) {}
1293
1294 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Text, TEXT, text);
1295 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(Data, DATA, data);
1296 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicList, LIST, list);
1297 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(DynamicStruct, STRUCT, struct);
1298 CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR(AnyPointer, ANY_POINTER, anyPointer);
1299
1300 #undef CAPNP_DECLARE_DYNAMIC_VALUE_CONSTRUCTOR
1301
1302 inline DynamicValue::Reader::Reader(DynamicCapability::Client& value)
1303 : type(CAPABILITY), capabilityValue(value) {}
1304 inline DynamicValue::Reader::Reader(DynamicCapability::Client&& value)
1305 : type(CAPABILITY), capabilityValue(kj::mv(value)) {}
1306 template <typename T, typename>
1307 inline DynamicValue::Reader::Reader(kj::Own<T>&& value)
1308 : type(CAPABILITY), capabilityValue(kj::mv(value)) {}
1309 inline DynamicValue::Builder::Builder(DynamicCapability::Client& value)
1310 : type(CAPABILITY), capabilityValue(value) {}
1311 inline DynamicValue::Builder::Builder(DynamicCapability::Client&& value)
1312 : type(CAPABILITY), capabilityValue(kj::mv(value)) {}
1313
1314 inline DynamicValue::Reader::Reader(const char* value): Reader(Text::Reader(value)) {}
1315
1316 #define CAPNP_DECLARE_TYPE(discrim, typeName) \
1317 template <> \
1318 struct DynamicValue::Reader::AsImpl<typeName> { \
1319 static ReaderFor<typeName> apply(const Reader& reader); \
1320 }; \
1321 template <> \
1322 struct DynamicValue::Builder::AsImpl<typeName> { \
1323 static BuilderFor<typeName> apply(Builder& builder); \
1324 };
1325
1326 //CAPNP_DECLARE_TYPE(VOID, Void)
1327 CAPNP_DECLARE_TYPE(BOOL, bool)
1328 CAPNP_DECLARE_TYPE(INT8, int8_t)
1329 CAPNP_DECLARE_TYPE(INT16, int16_t)
1330 CAPNP_DECLARE_TYPE(INT32, int32_t)
1331 CAPNP_DECLARE_TYPE(INT64, int64_t)
1332 CAPNP_DECLARE_TYPE(UINT8, uint8_t)
1333 CAPNP_DECLARE_TYPE(UINT16, uint16_t)
1334 CAPNP_DECLARE_TYPE(UINT32, uint32_t)
1335 CAPNP_DECLARE_TYPE(UINT64, uint64_t)
1336 CAPNP_DECLARE_TYPE(FLOAT32, float)
1337 CAPNP_DECLARE_TYPE(FLOAT64, double)
1338
1339 CAPNP_DECLARE_TYPE(TEXT, Text)
1340 CAPNP_DECLARE_TYPE(DATA, Data)
1341 CAPNP_DECLARE_TYPE(LIST, DynamicList)
1342 CAPNP_DECLARE_TYPE(STRUCT, DynamicStruct)
1343 CAPNP_DECLARE_TYPE(INTERFACE, DynamicCapability)
1344 CAPNP_DECLARE_TYPE(ENUM, DynamicEnum)
1345 CAPNP_DECLARE_TYPE(ANY_POINTER, AnyPointer)
1346 #undef CAPNP_DECLARE_TYPE
1347
1348 // CAPNP_DECLARE_TYPE(Void) causes gcc 4.7 to segfault. If I do it manually and remove the
1349 // ReaderFor<> and BuilderFor<> wrappers, it works.
1350 template <>
1351 struct DynamicValue::Reader::AsImpl<Void> {
1352 static Void apply(const Reader& reader);
1353 };
1354 template <>
1355 struct DynamicValue::Builder::AsImpl<Void> {
1356 static Void apply(Builder& builder);
1357 };
1358
1359 template <typename T>
1360 struct DynamicValue::Reader::AsImpl<T, Kind::ENUM> {
1361 static T apply(const Reader& reader) {
1362 return reader.as<DynamicEnum>().as<T>();
1363 }
1364 };
1365 template <typename T>
1366 struct DynamicValue::Builder::AsImpl<T, Kind::ENUM> {
1367 static T apply(Builder& builder) {
1368 return builder.as<DynamicEnum>().as<T>();
1369 }
1370 };
1371
1372 template <typename T>
1373 struct DynamicValue::Reader::AsImpl<T, Kind::STRUCT> {
1374 static typename T::Reader apply(const Reader& reader) {
1375 return reader.as<DynamicStruct>().as<T>();
1376 }
1377 };
1378 template <typename T>
1379 struct DynamicValue::Builder::AsImpl<T, Kind::STRUCT> {
1380 static typename T::Builder apply(Builder& builder) {
1381 return builder.as<DynamicStruct>().as<T>();
1382 }
1383 };
1384
1385 template <typename T>
1386 struct DynamicValue::Reader::AsImpl<T, Kind::LIST> {
1387 static typename T::Reader apply(const Reader& reader) {
1388 return reader.as<DynamicList>().as<T>();
1389 }
1390 };
1391 template <typename T>
1392 struct DynamicValue::Builder::AsImpl<T, Kind::LIST> {
1393 static typename T::Builder apply(Builder& builder) {
1394 return builder.as<DynamicList>().as<T>();
1395 }
1396 };
1397
1398 template <typename T>
1399 struct DynamicValue::Reader::AsImpl<T, Kind::INTERFACE> {
1400 static typename T::Client apply(const Reader& reader) {
1401 return reader.as<DynamicCapability>().as<T>();
1402 }
1403 };
1404 template <typename T>
1405 struct DynamicValue::Builder::AsImpl<T, Kind::INTERFACE> {
1406 static typename T::Client apply(Builder& builder) {
1407 return builder.as<DynamicCapability>().as<T>();
1408 }
1409 };
1410
1411 inline DynamicValue::Pipeline::Pipeline(std::nullptr_t n): type(UNKNOWN) {}
1412 inline DynamicValue::Pipeline::Pipeline(DynamicStruct::Pipeline&& value)
1413 : type(STRUCT), structValue(kj::mv(value)) {}
1414 inline DynamicValue::Pipeline::Pipeline(DynamicCapability::Client&& value)
1415 : type(CAPABILITY), capabilityValue(kj::mv(value)) {}
1416
1417 template <typename T>
1418 struct DynamicValue::Pipeline::AsImpl<T, Kind::STRUCT> {
1419 static typename T::Pipeline apply(Pipeline& pipeline) {
1420 return pipeline.releaseAs<DynamicStruct>().releaseAs<T>();
1421 }
1422 };
1423 template <typename T>
1424 struct DynamicValue::Pipeline::AsImpl<T, Kind::INTERFACE> {
1425 static typename T::Client apply(Pipeline& pipeline) {
1426 return pipeline.releaseAs<DynamicCapability>().releaseAs<T>();
1427 }
1428 };
1429 template <>
1430 struct DynamicValue::Pipeline::AsImpl<DynamicStruct, Kind::OTHER> {
1431 static PipelineFor<DynamicStruct> apply(Pipeline& pipeline);
1432 };
1433 template <>
1434 struct DynamicValue::Pipeline::AsImpl<DynamicCapability, Kind::OTHER> {
1435 static PipelineFor<DynamicCapability> apply(Pipeline& pipeline);
1436 };
1437
1438 // -------------------------------------------------------------------
1439
1440 template <typename T>
1441 typename T::Reader DynamicStruct::Reader::as() const {
1442 static_assert(kind<T>() == Kind::STRUCT,
1443 "DynamicStruct::Reader::as<T>() can only convert to struct types.");
1444 schema.requireUsableAs<T>();
1445 return typename T::Reader(reader);
1446 }
1447
1448 template <typename T>
1449 typename T::Builder DynamicStruct::Builder::as() {
1450 static_assert(kind<T>() == Kind::STRUCT,
1451 "DynamicStruct::Builder::as<T>() can only convert to struct types.");
1452 schema.requireUsableAs<T>();
1453 return typename T::Builder(builder);
1454 }
1455
1456 template <>
1457 inline DynamicStruct::Reader DynamicStruct::Reader::as<DynamicStruct>() const {
1458 return *this;
1459 }
1460 template <>
1461 inline DynamicStruct::Builder DynamicStruct::Builder::as<DynamicStruct>() {
1462 return *this;
1463 }
1464
1465 inline DynamicStruct::Reader DynamicStruct::Builder::asReader() const {
1466 return DynamicStruct::Reader(schema, builder.asReader());
1467 }
1468
1469 template <>
1470 inline AnyStruct::Reader DynamicStruct::Reader::as<AnyStruct>() const {
1471 return AnyStruct::Reader(reader);
1472 }
1473
1474 template <>
1475 inline AnyStruct::Builder DynamicStruct::Builder::as<AnyStruct>() {
1476 return AnyStruct::Builder(builder);
1477 }
1478
1479 template <typename T>
1480 typename T::Pipeline DynamicStruct::Pipeline::releaseAs() {
1481 static_assert(kind<T>() == Kind::STRUCT,
1482 "DynamicStruct::Pipeline::releaseAs<T>() can only convert to struct types.");
1483 schema.requireUsableAs<T>();
1484 return typename T::Pipeline(kj::mv(typeless));
1485 }
1486
1487 // -------------------------------------------------------------------
1488
1489 template <typename T>
1490 typename T::Reader DynamicList::Reader::as() const {
1491 static_assert(kind<T>() == Kind::LIST,
1492 "DynamicStruct::Reader::as<T>() can only convert to list types.");
1493 schema.requireUsableAs<T>();
1494 return typename T::Reader(reader);
1495 }
1496 template <typename T>
1497 typename T::Builder DynamicList::Builder::as() {
1498 static_assert(kind<T>() == Kind::LIST,
1499 "DynamicStruct::Builder::as<T>() can only convert to list types.");
1500 schema.requireUsableAs<T>();
1501 return typename T::Builder(builder);
1502 }
1503
1504 template <>
1505 inline DynamicList::Reader DynamicList::Reader::as<DynamicList>() const {
1506 return *this;
1507 }
1508 template <>
1509 inline DynamicList::Builder DynamicList::Builder::as<DynamicList>() {
1510 return *this;
1511 }
1512
1513 // -------------------------------------------------------------------
1514
1515 template <typename T, typename>
1516 inline DynamicCapability::Client::Client(T&& client)
1517 : Capability::Client(kj::mv(client)), schema(Schema::from<FromClient<T>>()) {}
1518
1519 template <typename T, typename>
1520 inline DynamicCapability::Client::Client(kj::Own<T>&& server)
1521 : Client(server->getSchema(), kj::mv(server)) {}
1522 template <typename T>
1523 inline DynamicCapability::Client::Client(InterfaceSchema schema, kj::Own<T>&& server)
1524 : Capability::Client(kj::mv(server)), schema(schema) {}
1525
1526 template <typename T, typename>
1527 typename T::Client DynamicCapability::Client::as() {
1528 static_assert(kind<T>() == Kind::INTERFACE,
1529 "DynamicCapability::Client::as<T>() can only convert to interface types.");
1530 schema.requireUsableAs<T>();
1531 return typename T::Client(hook->addRef());
1532 }
1533
1534 template <typename T, typename>
1535 typename T::Client DynamicCapability::Client::releaseAs() {
1536 static_assert(kind<T>() == Kind::INTERFACE,
1537 "DynamicCapability::Client::as<T>() can only convert to interface types.");
1538 schema.requireUsableAs<T>();
1539 return typename T::Client(kj::mv(hook));
1540 }
1541
1542 inline CallContext<DynamicStruct, DynamicStruct>::CallContext(
1543 CallContextHook& hook, StructSchema paramType, StructSchema resultType)
1544 : hook(&hook), paramType(paramType), resultType(resultType) {}
1545 inline DynamicStruct::Reader CallContext<DynamicStruct, DynamicStruct>::getParams() {
1546 return hook->getParams().getAs<DynamicStruct>(paramType);
1547 }
1548 inline void CallContext<DynamicStruct, DynamicStruct>::releaseParams() {
1549 hook->releaseParams();
1550 }
1551 inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::getResults(
1552 kj::Maybe<MessageSize> sizeHint) {
1553 return hook->getResults(sizeHint).getAs<DynamicStruct>(resultType);
1554 }
1555 inline DynamicStruct::Builder CallContext<DynamicStruct, DynamicStruct>::initResults(
1556 kj::Maybe<MessageSize> sizeHint) {
1557 return hook->getResults(sizeHint).initAs<DynamicStruct>(resultType);
1558 }
1559 inline void CallContext<DynamicStruct, DynamicStruct>::setResults(DynamicStruct::Reader value) {
1560 hook->getResults(value.totalSize()).setAs<DynamicStruct>(value);
1561 }
1562 inline void CallContext<DynamicStruct, DynamicStruct>::adoptResults(Orphan<DynamicStruct>&& value) {
1563 hook->getResults(MessageSize { 0, 0 }).adopt(kj::mv(value));
1564 }
1565 inline Orphanage CallContext<DynamicStruct, DynamicStruct>::getResultsOrphanage(
1566 kj::Maybe<MessageSize> sizeHint) {
1567 return Orphanage::getForMessageContaining(hook->getResults(sizeHint));
1568 }
1569 template <typename SubParams>
1570 inline kj::Promise<void> CallContext<DynamicStruct, DynamicStruct>::tailCall(
1571 Request<SubParams, DynamicStruct>&& tailRequest) {
1572 return hook->tailCall(kj::mv(tailRequest.hook));
1573 }
1574 inline void CallContext<DynamicStruct, DynamicStruct>::allowCancellation() {
1575 hook->allowCancellation();
1576 }
1577
1578 template <>
1579 inline DynamicCapability::Client Capability::Client::castAs<DynamicCapability>(
1580 InterfaceSchema schema) {
1581 return DynamicCapability::Client(schema, hook->addRef());
1582 }
1583
1584 // -------------------------------------------------------------------
1585
1586 template <typename T>
1587 ReaderFor<T> ConstSchema::as() const {
1588 return DynamicValue::Reader(*this).as<T>();
1589 }
1590
1591 } // namespace capnp
1592
1593 #endif // CAPNP_DYNAMIC_H_