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