annotate osx/include/capnp/compat/json.h @ 62:0994c39f1e94

Cap'n Proto v0.6 + build for OSX
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 22 May 2017 10:01:37 +0100
parents
children
rev   line source
cannam@62 1 // Copyright (c) 2015 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 #ifndef CAPNP_COMPAT_JSON_H_
cannam@62 23 #define CAPNP_COMPAT_JSON_H_
cannam@62 24
cannam@62 25 #include <capnp/schema.h>
cannam@62 26 #include <capnp/dynamic.h>
cannam@62 27 #include <capnp/compat/json.capnp.h>
cannam@62 28
cannam@62 29 namespace capnp {
cannam@62 30
cannam@62 31 class JsonCodec {
cannam@62 32 // Flexible class for encoding Cap'n Proto types as JSON, and decoding JSON back to Cap'n Proto.
cannam@62 33 //
cannam@62 34 // Typical usage:
cannam@62 35 //
cannam@62 36 // JsonCodec json;
cannam@62 37 //
cannam@62 38 // // encode
cannam@62 39 // kj::String encoded = json.encode(someStructReader);
cannam@62 40 //
cannam@62 41 // // decode
cannam@62 42 // json.decode(encoded, someStructBuilder);
cannam@62 43 //
cannam@62 44 // Advanced users can do fancy things like override the way certain types or fields are
cannam@62 45 // represented in JSON by registering handlers. See the unit test for an example.
cannam@62 46 //
cannam@62 47 // Notes:
cannam@62 48 // - When encoding, all primitive fields are always encoded, even if default-valued. Pointer
cannam@62 49 // fields are only encoded if they are non-null.
cannam@62 50 // - 64-bit integers are encoded as strings, since JSON "numbers" are double-precision floating
cannam@62 51 // points which cannot store a 64-bit integer without losing data.
cannam@62 52 // - NaNs and infinite floating point numbers are not allowed by the JSON spec, and so are encoded
cannam@62 53 // as null. This matches the behavior of `JSON.stringify` in at least Firefox and Chrome.
cannam@62 54 // - Data is encoded as an array of numbers in the range [0,255]. You probably want to register
cannam@62 55 // a handler that does something better, like maybe base64 encoding, but there are a zillion
cannam@62 56 // different ways people do this.
cannam@62 57 // - Encoding/decoding capabilities and AnyPointers requires registering a Handler, since there's
cannam@62 58 // no obvious default behavior.
cannam@62 59 // - When decoding, unrecognized field names are ignored. Note: This means that JSON is NOT a
cannam@62 60 // good format for receiving input from a human. Consider `capnp eval` or the SchemaParser
cannam@62 61 // library for human input.
cannam@62 62
cannam@62 63 public:
cannam@62 64 JsonCodec();
cannam@62 65 ~JsonCodec() noexcept(false);
cannam@62 66
cannam@62 67 // ---------------------------------------------------------------------------
cannam@62 68 // standard API
cannam@62 69
cannam@62 70 void setPrettyPrint(bool enabled);
cannam@62 71 // Enable to insert newlines, indentation, and other extra spacing into the output. The default
cannam@62 72 // is to use minimal whitespace.
cannam@62 73
cannam@62 74 void setMaxNestingDepth(size_t maxNestingDepth);
cannam@62 75 // Set maximum nesting depth when decoding JSON to prevent highly nested input from overflowing
cannam@62 76 // the call stack. The default is 64.
cannam@62 77
cannam@62 78 template <typename T>
cannam@62 79 kj::String encode(T&& value);
cannam@62 80 // Encode any Cap'n Proto value to JSON, including primitives and
cannam@62 81 // Dynamic{Enum,Struct,List,Capability}, but not DynamicValue (see below).
cannam@62 82
cannam@62 83 kj::String encode(DynamicValue::Reader value, Type type) const;
cannam@62 84 // Encode a DynamicValue to JSON. `type` is needed because `DynamicValue` itself does
cannam@62 85 // not distinguish between e.g. int32 and int64, which in JSON are handled differently. Most
cannam@62 86 // of the time, though, you can use the single-argument templated version of `encode()` instead.
cannam@62 87
cannam@62 88 void decode(kj::ArrayPtr<const char> input, DynamicStruct::Builder output) const;
cannam@62 89 // Decode JSON text directly into a struct builder. This only works for structs since lists
cannam@62 90 // need to be allocated with the correct size in advance.
cannam@62 91 //
cannam@62 92 // (Remember that any Cap'n Proto struct reader type can be implicitly cast to
cannam@62 93 // DynamicStruct::Reader.)
cannam@62 94
cannam@62 95 template <typename T>
cannam@62 96 Orphan<T> decode(kj::ArrayPtr<const char> input, Orphanage orphanage) const;
cannam@62 97 // Decode JSON text to any Cap'n Proto object (pointer value), allocated using the given
cannam@62 98 // orphanage. T must be specified explicitly and cannot be dynamic, e.g.:
cannam@62 99 //
cannam@62 100 // Orphan<MyType> orphan = json.decode<MyType>(text, orphanage);
cannam@62 101
cannam@62 102 template <typename T>
cannam@62 103 ReaderFor<T> decode(kj::ArrayPtr<const char> input) const;
cannam@62 104 // Decode JSON text into a primitive or capability value. T must be specified explicitly and
cannam@62 105 // cannot be dynamic, e.g.:
cannam@62 106 //
cannam@62 107 // uint32_t n = json.decode<uint32_t>(text);
cannam@62 108
cannam@62 109 Orphan<DynamicValue> decode(kj::ArrayPtr<const char> input, Type type, Orphanage orphanage) const;
cannam@62 110 Orphan<DynamicList> decode(
cannam@62 111 kj::ArrayPtr<const char> input, ListSchema type, Orphanage orphanage) const;
cannam@62 112 Orphan<DynamicStruct> decode(
cannam@62 113 kj::ArrayPtr<const char> input, StructSchema type, Orphanage orphanage) const;
cannam@62 114 DynamicCapability::Client decode(kj::ArrayPtr<const char> input, InterfaceSchema type) const;
cannam@62 115 DynamicEnum decode(kj::ArrayPtr<const char> input, EnumSchema type) const;
cannam@62 116 // Decode to a dynamic value, specifying the type schema.
cannam@62 117
cannam@62 118 // ---------------------------------------------------------------------------
cannam@62 119 // layered API
cannam@62 120 //
cannam@62 121 // You can separate text <-> JsonValue from JsonValue <-> T. These are particularly useful
cannam@62 122 // for calling from Handler implementations.
cannam@62 123
cannam@62 124 kj::String encodeRaw(JsonValue::Reader value) const;
cannam@62 125 void decodeRaw(kj::ArrayPtr<const char> input, JsonValue::Builder output) const;
cannam@62 126 // Translate JsonValue <-> text.
cannam@62 127
cannam@62 128 template <typename T>
cannam@62 129 void encode(T&& value, JsonValue::Builder output);
cannam@62 130 void encode(DynamicValue::Reader input, Type type, JsonValue::Builder output) const;
cannam@62 131 void decode(JsonValue::Reader input, DynamicStruct::Builder output) const;
cannam@62 132 template <typename T>
cannam@62 133 Orphan<T> decode(JsonValue::Reader input, Orphanage orphanage) const;
cannam@62 134 template <typename T>
cannam@62 135 ReaderFor<T> decode(JsonValue::Reader input) const;
cannam@62 136
cannam@62 137 Orphan<DynamicValue> decode(JsonValue::Reader input, Type type, Orphanage orphanage) const;
cannam@62 138 Orphan<DynamicList> decode(JsonValue::Reader input, ListSchema type, Orphanage orphanage) const;
cannam@62 139 Orphan<DynamicStruct> decode(
cannam@62 140 JsonValue::Reader input, StructSchema type, Orphanage orphanage) const;
cannam@62 141 DynamicCapability::Client decode(JsonValue::Reader input, InterfaceSchema type) const;
cannam@62 142 DynamicEnum decode(JsonValue::Reader input, EnumSchema type) const;
cannam@62 143
cannam@62 144 // ---------------------------------------------------------------------------
cannam@62 145 // specializing particular types
cannam@62 146
cannam@62 147 template <typename T, Style s = style<T>()>
cannam@62 148 class Handler;
cannam@62 149 // Implement this interface to specify a special encoding for a particular type or field.
cannam@62 150 //
cannam@62 151 // The templates are a bit ugly, but subclasses of this type essentially implement two methods,
cannam@62 152 // one to encode values of this type and one to decode values of this type. `encode()` is simple:
cannam@62 153 //
cannam@62 154 // void encode(const JsonCodec& codec, ReaderFor<T> input, JsonValue::Builder output) const;
cannam@62 155 //
cannam@62 156 // `decode()` is a bit trickier. When T is a struct (including DynamicStruct), it is:
cannam@62 157 //
cannam@62 158 // void decode(const JsonCodec& codec, JsonValue::Reader input, BuilderFor<T> output) const;
cannam@62 159 //
cannam@62 160 // However, when T is a primitive, decode() is:
cannam@62 161 //
cannam@62 162 // T decode(const JsonCodec& codec, JsonValue::Reader input) const;
cannam@62 163 //
cannam@62 164 // Or when T is any non-struct object (list, blob), decode() is:
cannam@62 165 //
cannam@62 166 // Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input, Orphanage orphanage) const;
cannam@62 167 //
cannam@62 168 // Or when T is an interface:
cannam@62 169 //
cannam@62 170 // T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const;
cannam@62 171 //
cannam@62 172 // Additionally, when T is a struct you can *optionally* also implement the orphan-returning form
cannam@62 173 // of decode(), but it will only be called when the struct would be allocated as an individual
cannam@62 174 // object, not as part of a list. This allows you to return "nullptr" in these cases to say that
cannam@62 175 // the pointer value should be null. This does not apply to list elements because struct list
cannam@62 176 // elements cannot ever be null (since Cap'n Proto encodes struct lists as a flat list rather
cannam@62 177 // than list-of-pointers).
cannam@62 178
cannam@62 179 template <typename T>
cannam@62 180 void addTypeHandler(Handler<T>& handler);
cannam@62 181 void addTypeHandler(Type type, Handler<DynamicValue>& handler);
cannam@62 182 void addTypeHandler(EnumSchema type, Handler<DynamicEnum>& handler);
cannam@62 183 void addTypeHandler(StructSchema type, Handler<DynamicStruct>& handler);
cannam@62 184 void addTypeHandler(ListSchema type, Handler<DynamicList>& handler);
cannam@62 185 void addTypeHandler(InterfaceSchema type, Handler<DynamicCapability>& handler);
cannam@62 186 // Arrange that whenever the type T appears in the message, your handler will be used to
cannam@62 187 // encode/decode it.
cannam@62 188 //
cannam@62 189 // Note that if you register a handler for a capability type, it will also apply to subtypes.
cannam@62 190 // Thus Handler<Capability> handles all capabilities.
cannam@62 191
cannam@62 192 template <typename T>
cannam@62 193 void addFieldHandler(StructSchema::Field field, Handler<T>& handler);
cannam@62 194 // Matches only the specific field. T can be a dynamic type. T must match the field's type.
cannam@62 195
cannam@62 196 private:
cannam@62 197 class HandlerBase;
cannam@62 198 struct Impl;
cannam@62 199
cannam@62 200 kj::Own<Impl> impl;
cannam@62 201
cannam@62 202 void encodeField(StructSchema::Field field, DynamicValue::Reader input,
cannam@62 203 JsonValue::Builder output) const;
cannam@62 204 void decodeArray(List<JsonValue>::Reader input, DynamicList::Builder output) const;
cannam@62 205 void decodeObject(List<JsonValue::Field>::Reader input, DynamicStruct::Builder output) const;
cannam@62 206 void addTypeHandlerImpl(Type type, HandlerBase& handler);
cannam@62 207 void addFieldHandlerImpl(StructSchema::Field field, Type type, HandlerBase& handler);
cannam@62 208 };
cannam@62 209
cannam@62 210 // =======================================================================================
cannam@62 211 // inline implementation details
cannam@62 212
cannam@62 213 template <typename T>
cannam@62 214 kj::String JsonCodec::encode(T&& value) {
cannam@62 215 typedef FromAny<kj::Decay<T>> Base;
cannam@62 216 return encode(DynamicValue::Reader(ReaderFor<Base>(kj::fwd<T>(value))), Type::from<Base>());
cannam@62 217 }
cannam@62 218
cannam@62 219 template <typename T>
cannam@62 220 inline Orphan<T> JsonCodec::decode(kj::ArrayPtr<const char> input, Orphanage orphanage) const {
cannam@62 221 return decode(input, Type::from<T>(), orphanage).template releaseAs<T>();
cannam@62 222 }
cannam@62 223
cannam@62 224 template <typename T>
cannam@62 225 inline ReaderFor<T> JsonCodec::decode(kj::ArrayPtr<const char> input) const {
cannam@62 226 static_assert(style<T>() == Style::PRIMITIVE || style<T>() == Style::CAPABILITY,
cannam@62 227 "must specify an orphanage to decode an object type");
cannam@62 228 return decode(input, Type::from<T>(), Orphanage()).getReader().template as<T>();
cannam@62 229 }
cannam@62 230
cannam@62 231 inline Orphan<DynamicList> JsonCodec::decode(
cannam@62 232 kj::ArrayPtr<const char> input, ListSchema type, Orphanage orphanage) const {
cannam@62 233 return decode(input, Type(type), orphanage).releaseAs<DynamicList>();
cannam@62 234 }
cannam@62 235 inline Orphan<DynamicStruct> JsonCodec::decode(
cannam@62 236 kj::ArrayPtr<const char> input, StructSchema type, Orphanage orphanage) const {
cannam@62 237 return decode(input, Type(type), orphanage).releaseAs<DynamicStruct>();
cannam@62 238 }
cannam@62 239 inline DynamicCapability::Client JsonCodec::decode(
cannam@62 240 kj::ArrayPtr<const char> input, InterfaceSchema type) const {
cannam@62 241 return decode(input, Type(type), Orphanage()).getReader().as<DynamicCapability>();
cannam@62 242 }
cannam@62 243 inline DynamicEnum JsonCodec::decode(kj::ArrayPtr<const char> input, EnumSchema type) const {
cannam@62 244 return decode(input, Type(type), Orphanage()).getReader().as<DynamicEnum>();
cannam@62 245 }
cannam@62 246
cannam@62 247 // -----------------------------------------------------------------------------
cannam@62 248
cannam@62 249 template <typename T>
cannam@62 250 void JsonCodec::encode(T&& value, JsonValue::Builder output) {
cannam@62 251 typedef FromAny<kj::Decay<T>> Base;
cannam@62 252 encode(DynamicValue::Reader(ReaderFor<Base>(kj::fwd<T>(value))), Type::from<Base>(), output);
cannam@62 253 }
cannam@62 254
cannam@62 255 template <typename T>
cannam@62 256 inline Orphan<T> JsonCodec::decode(JsonValue::Reader input, Orphanage orphanage) const {
cannam@62 257 return decode(input, Type::from<T>(), orphanage).template releaseAs<T>();
cannam@62 258 }
cannam@62 259
cannam@62 260 template <typename T>
cannam@62 261 inline ReaderFor<T> JsonCodec::decode(JsonValue::Reader input) const {
cannam@62 262 static_assert(style<T>() == Style::PRIMITIVE || style<T>() == Style::CAPABILITY,
cannam@62 263 "must specify an orphanage to decode an object type");
cannam@62 264 return decode(input, Type::from<T>(), Orphanage()).getReader().template as<T>();
cannam@62 265 }
cannam@62 266
cannam@62 267 inline Orphan<DynamicList> JsonCodec::decode(
cannam@62 268 JsonValue::Reader input, ListSchema type, Orphanage orphanage) const {
cannam@62 269 return decode(input, Type(type), orphanage).releaseAs<DynamicList>();
cannam@62 270 }
cannam@62 271 inline Orphan<DynamicStruct> JsonCodec::decode(
cannam@62 272 JsonValue::Reader input, StructSchema type, Orphanage orphanage) const {
cannam@62 273 return decode(input, Type(type), orphanage).releaseAs<DynamicStruct>();
cannam@62 274 }
cannam@62 275 inline DynamicCapability::Client JsonCodec::decode(
cannam@62 276 JsonValue::Reader input, InterfaceSchema type) const {
cannam@62 277 return decode(input, Type(type), Orphanage()).getReader().as<DynamicCapability>();
cannam@62 278 }
cannam@62 279 inline DynamicEnum JsonCodec::decode(JsonValue::Reader input, EnumSchema type) const {
cannam@62 280 return decode(input, Type(type), Orphanage()).getReader().as<DynamicEnum>();
cannam@62 281 }
cannam@62 282
cannam@62 283 // -----------------------------------------------------------------------------
cannam@62 284
cannam@62 285 class JsonCodec::HandlerBase {
cannam@62 286 // Internal helper; ignore.
cannam@62 287 public:
cannam@62 288 virtual void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
cannam@62 289 JsonValue::Builder output) const = 0;
cannam@62 290 virtual Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 291 Type type, Orphanage orphanage) const;
cannam@62 292 virtual void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 293 DynamicStruct::Builder output) const;
cannam@62 294 };
cannam@62 295
cannam@62 296 template <typename T>
cannam@62 297 class JsonCodec::Handler<T, Style::POINTER>: private JsonCodec::HandlerBase {
cannam@62 298 public:
cannam@62 299 virtual void encode(const JsonCodec& codec, ReaderFor<T> input,
cannam@62 300 JsonValue::Builder output) const = 0;
cannam@62 301 virtual Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 302 Orphanage orphanage) const = 0;
cannam@62 303
cannam@62 304 private:
cannam@62 305 void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
cannam@62 306 JsonValue::Builder output) const override final {
cannam@62 307 encode(codec, input.as<T>(), output);
cannam@62 308 }
cannam@62 309 Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 310 Type type, Orphanage orphanage) const override final {
cannam@62 311 return decode(codec, input, orphanage);
cannam@62 312 }
cannam@62 313 friend class JsonCodec;
cannam@62 314 };
cannam@62 315
cannam@62 316 template <typename T>
cannam@62 317 class JsonCodec::Handler<T, Style::STRUCT>: private JsonCodec::HandlerBase {
cannam@62 318 public:
cannam@62 319 virtual void encode(const JsonCodec& codec, ReaderFor<T> input,
cannam@62 320 JsonValue::Builder output) const = 0;
cannam@62 321 virtual void decode(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 322 BuilderFor<T> output) const = 0;
cannam@62 323 virtual Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 324 Orphanage orphanage) const {
cannam@62 325 // If subclass does not override, fall back to regular version.
cannam@62 326 auto result = orphanage.newOrphan<T>();
cannam@62 327 decode(codec, input, result.get());
cannam@62 328 return result;
cannam@62 329 }
cannam@62 330
cannam@62 331 private:
cannam@62 332 void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
cannam@62 333 JsonValue::Builder output) const override final {
cannam@62 334 encode(codec, input.as<T>(), output);
cannam@62 335 }
cannam@62 336 Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 337 Type type, Orphanage orphanage) const override final {
cannam@62 338 return decode(codec, input, orphanage);
cannam@62 339 }
cannam@62 340 void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 341 DynamicStruct::Builder output) const override final {
cannam@62 342 decode(codec, input, output.as<T>());
cannam@62 343 }
cannam@62 344 friend class JsonCodec;
cannam@62 345 };
cannam@62 346
cannam@62 347 template <>
cannam@62 348 class JsonCodec::Handler<DynamicStruct>: private JsonCodec::HandlerBase {
cannam@62 349 // Almost identical to Style::STRUCT except that we pass the struct type to decode().
cannam@62 350
cannam@62 351 public:
cannam@62 352 virtual void encode(const JsonCodec& codec, DynamicStruct::Reader input,
cannam@62 353 JsonValue::Builder output) const = 0;
cannam@62 354 virtual void decode(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 355 DynamicStruct::Builder output) const = 0;
cannam@62 356 virtual Orphan<DynamicStruct> decode(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 357 StructSchema type, Orphanage orphanage) const {
cannam@62 358 // If subclass does not override, fall back to regular version.
cannam@62 359 auto result = orphanage.newOrphan(type);
cannam@62 360 decode(codec, input, result.get());
cannam@62 361 return result;
cannam@62 362 }
cannam@62 363
cannam@62 364 private:
cannam@62 365 void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
cannam@62 366 JsonValue::Builder output) const override final {
cannam@62 367 encode(codec, input.as<DynamicStruct>(), output);
cannam@62 368 }
cannam@62 369 Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 370 Type type, Orphanage orphanage) const override final {
cannam@62 371 return decode(codec, input, type.asStruct(), orphanage);
cannam@62 372 }
cannam@62 373 void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 374 DynamicStruct::Builder output) const override final {
cannam@62 375 decode(codec, input, output.as<DynamicStruct>());
cannam@62 376 }
cannam@62 377 friend class JsonCodec;
cannam@62 378 };
cannam@62 379
cannam@62 380 template <typename T>
cannam@62 381 class JsonCodec::Handler<T, Style::PRIMITIVE>: private JsonCodec::HandlerBase {
cannam@62 382 public:
cannam@62 383 virtual void encode(const JsonCodec& codec, T input, JsonValue::Builder output) const = 0;
cannam@62 384 virtual T decode(const JsonCodec& codec, JsonValue::Reader input) const = 0;
cannam@62 385
cannam@62 386 private:
cannam@62 387 void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
cannam@62 388 JsonValue::Builder output) const override final {
cannam@62 389 encode(codec, input.as<T>(), output);
cannam@62 390 }
cannam@62 391 Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 392 Type type, Orphanage orphanage) const override final {
cannam@62 393 return decode(codec, input);
cannam@62 394 }
cannam@62 395 friend class JsonCodec;
cannam@62 396 };
cannam@62 397
cannam@62 398 template <typename T>
cannam@62 399 class JsonCodec::Handler<T, Style::CAPABILITY>: private JsonCodec::HandlerBase {
cannam@62 400 public:
cannam@62 401 virtual void encode(const JsonCodec& codec, typename T::Client input,
cannam@62 402 JsonValue::Builder output) const = 0;
cannam@62 403 virtual typename T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const = 0;
cannam@62 404
cannam@62 405 private:
cannam@62 406 void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
cannam@62 407 JsonValue::Builder output) const override final {
cannam@62 408 encode(codec, input.as<T>(), output);
cannam@62 409 }
cannam@62 410 Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
cannam@62 411 Type type, Orphanage orphanage) const override final {
cannam@62 412 return orphanage.newOrphanCopy(decode(codec, input));
cannam@62 413 }
cannam@62 414 friend class JsonCodec;
cannam@62 415 };
cannam@62 416
cannam@62 417 template <typename T>
cannam@62 418 inline void JsonCodec::addTypeHandler(Handler<T>& handler) {
cannam@62 419 addTypeHandlerImpl(Type::from<T>(), handler);
cannam@62 420 }
cannam@62 421 inline void JsonCodec::addTypeHandler(Type type, Handler<DynamicValue>& handler) {
cannam@62 422 addTypeHandlerImpl(type, handler);
cannam@62 423 }
cannam@62 424 inline void JsonCodec::addTypeHandler(EnumSchema type, Handler<DynamicEnum>& handler) {
cannam@62 425 addTypeHandlerImpl(type, handler);
cannam@62 426 }
cannam@62 427 inline void JsonCodec::addTypeHandler(StructSchema type, Handler<DynamicStruct>& handler) {
cannam@62 428 addTypeHandlerImpl(type, handler);
cannam@62 429 }
cannam@62 430 inline void JsonCodec::addTypeHandler(ListSchema type, Handler<DynamicList>& handler) {
cannam@62 431 addTypeHandlerImpl(type, handler);
cannam@62 432 }
cannam@62 433 inline void JsonCodec::addTypeHandler(InterfaceSchema type, Handler<DynamicCapability>& handler) {
cannam@62 434 addTypeHandlerImpl(type, handler);
cannam@62 435 }
cannam@62 436
cannam@62 437 template <typename T>
cannam@62 438 inline void JsonCodec::addFieldHandler(StructSchema::Field field, Handler<T>& handler) {
cannam@62 439 addFieldHandlerImpl(field, Type::from<T>(), handler);
cannam@62 440 }
cannam@62 441
cannam@62 442 template <> void JsonCodec::addTypeHandler(Handler<DynamicValue>& handler)
cannam@62 443 KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
cannam@62 444 "try specifying a specific type schema as the first parameter");
cannam@62 445 template <> void JsonCodec::addTypeHandler(Handler<DynamicEnum>& handler)
cannam@62 446 KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
cannam@62 447 "try specifying a specific type schema as the first parameter");
cannam@62 448 template <> void JsonCodec::addTypeHandler(Handler<DynamicStruct>& handler)
cannam@62 449 KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
cannam@62 450 "try specifying a specific type schema as the first parameter");
cannam@62 451 template <> void JsonCodec::addTypeHandler(Handler<DynamicList>& handler)
cannam@62 452 KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
cannam@62 453 "try specifying a specific type schema as the first parameter");
cannam@62 454 template <> void JsonCodec::addTypeHandler(Handler<DynamicCapability>& handler)
cannam@62 455 KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
cannam@62 456 "try specifying a specific type schema as the first parameter");
cannam@62 457 // TODO(someday): Implement support for registering handlers that cover thinsg like "all structs"
cannam@62 458 // or "all lists". Currently you can only target a specific struct or list type.
cannam@62 459
cannam@62 460 } // namespace capnp
cannam@62 461
cannam@62 462 #endif // CAPNP_COMPAT_JSON_H_