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