annotate osx/include/capnp/dynamic.h @ 83:ae30d91d2ffe

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