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