JSON Voorhees
Killer JSON for C++
serialization_builder.hpp
Go to the documentation of this file.
1 /** \file jsonv/serialization_builder.hpp
2  * DSL for building \c formats.
3  *
4  * Copyright (c) 2015-2019 by Travis Gockel. All rights reserved.
5  *
6  * This program is free software: you can redistribute it and/or modify it under the terms of the Apache License
7  * as published by the Apache Software Foundation, either version 2 of the License, or (at your option) any later
8  * version.
9  *
10  * \author Travis Gockel (travis@gockelhut.com)
11 **/
12 #ifndef __JSONV_SERIALIZATION_BUILDER_HPP_INCLUDED__
13 #define __JSONV_SERIALIZATION_BUILDER_HPP_INCLUDED__
14 
15 #include <jsonv/config.hpp>
16 #include <jsonv/serialization.hpp>
18 
19 #include <deque>
20 #include <map>
21 #include <memory>
22 #include <set>
23 #include <type_traits>
24 
25 namespace jsonv
26 {
27 
28 /** \page serialization_builder_dsl Serialization Builder DSL
29  *
30  * Most applications tend to have a lot of structure types. While it is possible to write an \c extractor and
31  * \c serializer (or \c adapter) for each type, this can get a little bit tedious. Beyond that, it is very difficult to
32  * look at the contents of adapter code and discover what the JSON might actually look like. The builder DSL is meant
33  * to solve these issues by providing a convenient way to describe conversion operations for your C++ types.
34  *
35  * At the end of the day, the goal is to take some C++ structures like this:
36  *
37  * \code
38  * struct person
39  * {
40  * std::string first_name;
41  * std::string last_name;
42  * int age;
43  * std::string role;
44  * };
45  *
46  * struct company
47  * {
48  * std::string name;
49  * bool certified;
50  * std::vector<person> employees;
51  * std::list<person> candidates;
52  * };
53  * \endcode
54  *
55  * ...and easily convert it to an from a JSON representation that looks like this:
56  *
57  * \code
58  * {
59  * "name": "Paul's Construction",
60  * "certified": false,
61  * "employees": [
62  * {
63  * "first_name": "Bob",
64  * "last_name": "Builder",
65  * "age": 29
66  * },
67  * {
68  * "first_name": "James",
69  * "last_name": "Johnson",
70  * "age": 38,
71  * "role": "Foreman"
72  * }
73  * ],
74  * "candidates": [
75  * {
76  * "firstname": "Adam",
77  * "lastname": "Ant"
78  * }
79  * ]
80  * }
81  * \endcode
82  *
83  * To define a \c formats for this \c person type using the serialization builder DSL, you would say:
84  *
85  * \code
86  * jsonv::formats fmts =
87  * jsonv::formats_builder()
88  * .type<person>()
89  * .member("first_name", &person::first_name)
90  * .alternate_name("firstname")
91  * .member("last_name", &person::last_name)
92  * .alternate_name("lastname")
93  * .member("age", &person::age)
94  * .until({ 6,1 })
95  * .default_value(21)
96  * .default_on_null()
97  * .check_input([] (int value) { if (value < 0) throw std::logic_error("Age must be positive."); })
98  * .member("role", &person::role)
99  * .since({ 2,0 })
100  * .default_value("Builder")
101  * .type<company>()
102  * .member("name", &company::name)
103  * .member("certified", &company::certified)
104  * .member("employees", &company::employees)
105  * .member("candidates", &company::candidates)
106  * .register_containers<company, std::vector, std::list>()
107  * .check_references(jsonv::formats::defaults())
108  * ;
109  * \endcode
110  *
111  * \section Reference
112  *
113  * The DSL is made up of three major parts:
114  *
115  * 1. \e formats -- modifies a \c jsonv::formats object by adding new type adapters to it
116  * 2. \e type -- modifies the behavior of a \c jsonv::adapter by adding new members to it
117  * 3. \e member -- modifies an individual member inside of a specific type
118  *
119  * Each successive function call transforms your context. \e Narrowing calls make your context more specific; for
120  * example, calling \c type from a \e formats context allows you to modify a specific type. \e Widening calls make the
121  * context less specific and are always available; for example, when in the \e member context, you can still call
122  * \c type from the \e formats context to specify a new type.
123  *
124  * \dot
125  * digraph serialization_builder_dsl {
126  * formats [label="formats"]
127  * type [label="type"]
128  * member [label="member"]
129  *
130  * formats -> formats
131  * formats -> type
132  * type -> formats
133  * type -> type
134  * type -> member
135  * member -> formats
136  * member -> type
137  * member -> member
138  * }
139  * \enddot
140  *
141  * \subsection serialization_builder_dsl_ref_formats Formats Context
142  *
143  * Commands in this section modify the behavior of the underlying \c jsonv::formats object.
144  *
145  * \subsubsection serialization_builder_dsl_ref_formats_level Level
146  *
147  * \paragraph serialization_builder_dsl_ref_formats_level_check_references check_references
148  *
149  * - <tt>check_references(formats)</tt>
150  * - <tt>check_references(formats, std::string name)</tt>
151  * - <tt>check_references(formats::list)</tt>
152  * - <tt>check_references(formats::list, std::string name)</tt>
153  * - <tt>check_references()</tt>
154  * - <tt>check_references(std::string name)</tt>
155  *
156  * Tests that every type referenced by the members of the output of the DSL have an \c extractor and a \c serializer.
157  * The provided \c formats is used to draw extra types from (a common value is \c jsonv::formats::defaults). In other
158  * words, it asks the question: If the \c formats from this DSL was combined with these other \c formats, could all of
159  * the types be encoded and decoded?
160  *
161  * This does not mutate the DSL in any way. On successful verification, it will appear that nothing happened. If the
162  * verification is not successful, an exception will be thrown with the offending types in the message. For example:
163  *
164  * \code
165  * There are 2 types referenced that the formats do not know how to serialize:
166  * - date_type (referenced by: name_space::foo, other::name::space::bar)
167  * - tree
168  * \endcode
169  *
170  * If \a name is provided, the value will be output to the error message on failure. This can be useful if you have
171  * multiple \c check_references statements and wish to more easily determine the failing \c formats combination from
172  * the error message alone.
173  *
174  * \note
175  * This is evaluated \e immediately, so it is best to call this function as the very last step in the DSL.
176  *
177  * \code
178  * .check_references(jsonv::formats::defaults())
179  * \endcode
180  *
181  * \paragraph serialization_builder_dsl_ref_formats_level_reference_type reference_type
182  *
183  * - <tt>reference_type(std::type_index type)</tt>
184  * - <tt>reference_type(std::type_index type, std::type_index from)</tt>
185  *
186  * Explicitly add a reference to the provided \a type in the DSL. If \a from is provided, also add a back reference for
187  * tracking purposes. The \a from field is useful for tracking \e why the \a type is referenced.
188  *
189  * Type references are used in \ref serialization_builder_dsl_ref_formats_level_check_references to both check and
190  * generate error messages if the \c formats the DSL is building cannot fully create and extract JSON values. You do
191  * not usually have to call this, as each call to \ref serialization_builder_dsl_ref_type_narrowing_member calls this
192  * automatically.
193  *
194  * \code
195  * .reference_type(std::type_index(typeid(int)), std::type_index(typeid(my_type)))
196  * .reference_type(std::type_index(typeid(my_type))
197  * \endcode
198  *
199  * \paragraph serialization_builder_dsl_ref_formats_level_register_adapter register_adapter
200  *
201  * - <tt>register_adapter(const adapter*)</tt>
202  * - <tt>register_adapter(std::shared_ptr&lt;const adapter&gt;)</tt>
203  *
204  * Register an arbitrary \c adapter with the \c formats we are currently building. This is useful for integrating with
205  * type adapters that do not (or can not) use the DSL.
206  *
207  * \code
208  * .register_adapter(my_type::get_adapter())
209  * \endcode
210  *
211  * \paragraph serialization_builder_dsl_ref_formats_level_register_optional register_optional
212  *
213  * - <tt>register_optional&lt;TOptional&gt;()</tt>
214  *
215  * Similar to \c register_adapter, but automatically create an <tt>optional_adapter&lt;TOptional&gt;</tt> to store.
216  *
217  * \code
218  * .register_optional<std::optional<int>>()
219  * .register_optional<boost::optional<double>>()
220  * \endcode
221  *
222  * \paragraph serialization_builder_dsl_ref_formats_level_register_container register_container
223  *
224  * - <tt>register_container&lt;TContainer&gt;()</tt>
225  *
226  * Similar to \c register_adapter, but automatically create a <tt>container_adapter&lt;TContainer&gt;</tt> to store.
227  *
228  * \code
229  * .register_container<std::vector<int>>()
230  * .register_container<std::list<std::string>>()
231  * \endcode
232  *
233  * \paragraph serialization_builder_dsl_ref_formats_level_register_containers register_containers
234  *
235  * - <tt>register_containers&lt;T, template &lt;T, ...&gt;... TTContainer&gt;</tt>
236  *
237  * Convenience function for calling \c register_container for multiple containers with the same \c value_type.
238  * Unfortunately, it only supports varying the first template parameter of the \c TTContainer types, so if you wish to
239  * do something like vary the allocator, you will have to either call \c register_container multiple times or use a
240  * template alias.
241  *
242  * \code
243  * .register_containers<int, std::list, std::deque>()
244  * .register_containers<double, std::vector, std::set>()
245  * \endcode
246  *
247  * \note
248  * Not supported in MSVC 14 (CTP 5).
249  *
250  * \paragraph serialization_builder_dsl_ref_formats_level_register_wrapper register_wrapper
251  *
252  * - <tt>register_wrapper&lt;TWrapper&gt;()</tt>
253  *
254  * Similar to \c register_adapter, but automatically create an <tt>wrapper_adapter&lt;TWrapper&gt;</tt> to store.
255  *
256  * \code
257  * .register_optional<std::optional<int>>()
258  * .register_optional<boost::optional<double>>()
259  * \endcode
260  *
261  * \paragraph serialization_builder_dsl_ref_formats_level_enum_type enum_type
262  *
263  * - <tt>enum_type&lt;TEnum&gt;(std::string name, std::initializer_list&lt;std::pair&lt;TEnum, jsonv::value&gt;&gt;)</tt>
264  * - <tt>enum_type_icase&lt;TEnum&gt;(std::string name, std::initializer_list&lt;std::pair&lt;TEnum, jsonv::value&gt;&gt;)</tt>
265  *
266  * Create an adapter for the \c TEnum type with a mapping of C++ values to JSON values and vice versa. The most common
267  * use of this is to map \c enum values in C++ to string representations in JSON. \c TEnum is not restricted to types
268  * which are \c enum, but can be anything which you would like to restrict to a limited subset of possible values.
269  * Likewise, JSON representations are not restricted to being of \c kind::string.
270  *
271  * The sibling function \c enum_type_icase will create an adapter which uses case-insensitive checking when converting
272  * to C++ values in \c extract.
273  *
274  * \code
275  * .enum_type<ring>("ring",
276  * {
277  * { ring::fire, "fire" },
278  * { ring::wind, "wind" },
279  * { ring::earth, "earth" },
280  * { ring::water, "water" },
281  * { ring::heart, "heart" }, // "heart" is preferred for to_json
282  * { ring::heart, "useless" }, // "useless" is interpreted as ring::heart in extract
283  * { ring::fire, 1 }, // the JSON value 1 will also be interpreted as ring::fire in extract
284  * { ring::ussr, "wind" }, // old C++ value ring::ussr will get output as "wind"
285  * }
286  * )
287  * .enum_type_icase<int>("integer",
288  * {
289  * { 0, "zero" },
290  * { 0, "naught" },
291  * { 1, "one" },
292  * { 2, "two" },
293  * { 3, "three" },
294  * }
295  * )
296  * \endcode
297  *
298  * \see enum_adapter
299  *
300  * \paragraph serialization_builder_dls_ref_formats_level_polymorphic_type polymorphic_type
301  *
302  * - <tt>polymorphic_type<&lt;TPointer&gt;(std::string discrimination_key);</tt>
303  *
304  * Create an adapter for the \c TPointer type (usually \c std::shared_ptr or \c std::unique_ptr) that knows how to
305  * serialize and deserialize one or more types that can be polymorphically represented by \c TPointer, i.e. derived
306  * types. It uses a discrimination key to determine which concrete type should be instantiated when extracting values
307  * from json.
308  *
309  * \code
310  * .polymorphic_type<std::unique_ptr<base>>("type")
311  * .subtype<derived_1>("derived_1")
312  * .subtype<derived_2>("derived_2", keyed_subtype_action::check)
313  * .subtype<derived_3>("derived_3", keyed_subtype_action::insert);
314  * \endcode
315  *
316  * The \ref keyed_subtype_action can be used to configure the adapter to make sure that the discrimination key was
317  * correctly serialized (\ref keyed_subtype_action::check) or to insert the discrimination key for the underlying type
318  * so that the underlying type doesn't need to do that itself (\ref keyed_subtype_action::insert). The default is to do
319  * nothing (\ref keyed_subtype_action::none).
320  *
321  * \paragraph serialization_builder_dsl_ref_formats_level_extend extend
322  *
323  * - <tt>extend(std::function&lt;void (formats_builder&amp;)&gt; func)</tt>
324  *
325  * Extend the \c formats_builder with the provided \a func by passing the current builder to it. This provides a more
326  * convenient way to call helper functions.
327  *
328  * \code
329  * jsonv::formats_builder builder;
330  * foo(builder);
331  * bar(builder);
332  * baz(builder);
333  * \endcode
334  *
335  * This can be done equivalently with:
336  * \code
337  * jsonv::formats_builder()
338  * .extend(foo)
339  * .extend(bar)
340  * .extend(baz)
341  * \endcode
342  *
343  * \paragraph serialization_builder_dsl_ref_formats_level_on_duplicate_type on_duplicate_type
344  *
345  * - <tt>on_duplicate_type(on_duplicate_type_action action);</tt>
346  *
347  * Set what action to take when attempting to register an adapter, but there is already an adapter for that type in the
348  * formats. The default is to throw a \ref duplicate_type_error exception (\ref duplicate_type_action::exception), but
349  * the \c formats_builder can also be configured to ignore the duplicate (\ref duplicate_type_action::ignore), or to
350  * replace the existing adapter with the new one (\ref duplicate_type_action::replace). This is useful when calling
351  * multiple \c extend methods that may add common types to the \c formats_builder.
352  *
353  * \subsubsection serialization_builder_dsl_ref_formats_narrowing Narrowing
354  *
355  * \paragraph serialization_builder_dsl_ref_formats_narrowing_type type&lt;T&gt;
356  *
357  * - <tt>type&lt;T&gt;()</tt>
358  * - <tt>type&lt;T&gt;(std::function&lt;void (adapter_builder&lt;T&gt;&amp;)&gt; func)</tt>
359  *
360  * Create an \c adapter for type \c T and begin building the members for it. If \a func is provided, it will be called
361  * with the adapter_builder&lt;T&gt; this call to \c type creates, which can be used for creating common extension
362  * functions.
363  *
364  * \code
365  * .type<my_type>()
366  * .member(...)
367  * .
368  * .
369  * .
370  * \endcode
371  *
372  *
373  * \subsection serialization_builder_dsl_ref_type Type Context
374  *
375  * Commands in this section modify the behavior of the \c jsonv::adapter for a particular type.
376  *
377  * \subsubsection serialization_builder_dsl_ref_type_level Level
378  *
379  * \paragraph serialization_builder_dsl_ref_type_level_pre_extract pre_extract
380  *
381  * - <tt>pre_extract(std::function&lt;void (const extraction_context& context, const value& from)&gt; perform)</tt>
382  *
383  * Call the given \a perform function during the \c extract operation, but before performing any extraction. This can
384  * be called multiple times -- all functions will be called in the order they are provided.
385  *
386  * \paragraph serialization_builder_dsl_ref_type_level_post_extract post_extract
387  *
388  * - <tt>post_extract(std::function&lt;T (const extraction_context& context, T&& out)&gt; perform)</tt>
389  *
390  * Call the given \a perform function after the \c extract operation. All functions will be called in the order they
391  * are provided. This allows validation methods to be called on the extracted object as part of extraction.
392  * Postprocessing functions are allowed to mutate the extracted object.
393  *
394  * \paragraph serialization_builder_dsl_ref_type_level_default_on_null type_default_on_null
395  *
396  * - <tt>type_default_on_null()</tt>
397  * - <tt>type_default_on_null(bool on)</tt>
398  *
399  * If the JSON value \c null is in the input, should this type take on some default?
400  * This should be used with \ref serialization_builder_dsl_ref_type_level_type_default_value type_default_value.
401  *
402  * \paragraph serialization_builder_dsl_ref_type_level_type_default_value
403  *
404  * - <tt>type_default_value(T value)</tt>
405  * - <tt>type_default_value(std::function&lt;T (const extraction_context& context)&gt;)</tt>
406  *
407  * What value should be used to create the default for this type?
408  *
409  * \code
410  * .type<my_type>()
411  * .type_default_on_null()
412  * .type_default_value(my_type("default"))
413  * \endcode
414  *
415  * \paragraph serialization_builder_dsl_ref_type_level_on_extract_extra_keys on_extract_extra_keys
416  *
417  * - <tt>on_extract_extra_keys(std::function&lt;void (const extraction_context& context,
418  * const value& from,
419  * std::set&lt;std::string&gt; extra_keys)&gt; action
420  * )</tt>
421  *
422  * When extracting, perform some \a action if extra keys are provided. By default, extra keys are usually simply
423  * ignored, so this is useful if you wish to throw an exception (or anything you want).
424  *
425  * \code
426  * .type<my_type>()
427  * .member("x", &my_type::x)
428  * .member("y", &my_type::y)
429  * .on_extract_extra_keys([] (const extraction_context&, const value&, std::set<std::string> extra_keys)
430  * {
431  * throw extracted_extra_keys("my_type", std::move(extra_keys));
432  * }
433  * )
434  * \endcode
435  *
436  * There is a convenience function named \c throw_extra_keys_extraction_error which does this for you.
437  *
438  * \code
439  * .type<my_type>()
440  * .member("x", &my_type::x)
441  * .member("y", &my_type::y)
442  * .on_extract_extra_keys(jsonv::throw_extra_keys_extraction_error)
443  * \endcode
444  *
445  * \subsubsection serialization_builder_dsl_ref_type_narrowing Narrowing
446  *
447  * \paragraph serialization_builder_dsl_ref_type_narrowing_member member
448  *
449  * - <tt>member(std::string name, TMember T::*selector)</tt>
450  * - <tt>member(std::string name, const TMember& (*access)(const T&), void (*mutate)(T&, TMember&&))</tt>
451  * - <tt>member(std::string name, const TMember& (T::*access)() const, TMember& (T::*mutable_access)())</tt>
452  * - <tt>member(std::string name, const TMember& (T::*access)() const, void (T::*mutate)(TMember))</tt>
453  * - <tt>member(std::string name, const TMember& (T::*access)() const, void (T::*mutate)(TMember&&))</tt>
454  *
455  * Adds a member to the type we are currently building. By default, the member will be serialized with the key of the
456  * given \a name and the extractor will search for the given \a name. If you wish to change properties of this field,
457  * use the \ref serialization_builder_dsl_ref_member.
458  *
459  * \code
460  * .type<my_type>()
461  * .member("x", &my_type::x)
462  * .member("y", &my_type::y)
463  * .member("thing", &my_type::get_thing, &my_type::set_thing)
464  * \endcode
465  *
466  *
467  * \subsection serialization_builder_dsl_ref_member Member Context
468  *
469  * Commands in this section modify the behavior of a particular member. Here, \c T refers to the containing type (the
470  * one we are adding a member to) and \c TMember refers to the type of the member we are modifying.
471  *
472  * \subsubsection serialization_builder_dsl_ref_member_level Level
473  *
474  * \paragraph serialization_builder_dsl_ref_member_level_after after
475  *
476  * - <tt>after(version)</tt>
477  *
478  * Only serialize this member if the \c serialization_context::version is not \c version::empty and is greater than or
479  * equal to the provided \c version.
480  *
481  * \paragraph serialization_builder_dsl_ref_member_level_alternate_name alternate_name
482  *
483  * - <tt>alternate_name(std::string name)</tt>
484  *
485  * Provide an alternate name to search for when extracting this member. If a user provides values for multiple names,
486  * preference is given to names earlier in the list, starting with the original given name.
487  *
488  * \paragraph serialization_builder_dsl_ref_member_level_before before
489  *
490  * - <tt>before(version)</tt>
491  *
492  * Only serialize this member if the \c serialization_context::version is not \c version::empty and is less than or
493  * equal to the provided \c version.
494  *
495  * \paragraph serialization_builder_dsl_ref_member_level_check_input check_input
496  *
497  * - <tt>check_input(std::function&lt;void (const TMember&)&gt; check)</tt>
498  * - <tt>check_input(std::function&lt;bool (const TMember&)&gt; check, std::function&lt;void (const TMember&)&gt; thrower)</tt>
499  * - <tt>check_input(std::function&lt;bool (const TMember&)&gt; check, TException ex)</tt>
500  *
501  * Checks the extracted value with the given \a check function. In the first form, you are expected to throw inside the
502  * function. In the latter forms, the second parameter will be invoked (in the case of \a thrower) or thrown directly
503  * (in the case of \a ex).
504  *
505  * \code
506  * .member("x", &my_type::x)
507  * .check_input([] (int x) { if (x < 0) throw std::logic_error("x must be greater than 0"); })
508  * .check_input([] (int x) { return x < 100; }, [] (int x) { throw exceptions::less_than(100, x); })
509  * .check_input([] (int x) { return x % 2 == 0; }, std::logic_error("x must be divisible by 2"))
510  * \endcode
511  *
512  * \paragraph serialization_builder_dsl_ref_member_level_default_value default_value
513  *
514  * - <tt>default_value(TMember value)</tt>
515  * - <tt>default_value(std::function&lt;TMember (const extraction_context&, const value&)&gt; create)</tt>
516  *
517  * Provide a default value for this member if no key is found when extracting. You can use the function implementation
518  * to synthesize the key however you want.
519  *
520  * \code
521  * .member("x", &my_type::x)
522  * .default_value(10)
523  * \endcode
524  *
525  * \paragraph serialization_builder_dsl_ref_member_level_default_on_null default_on_null
526  *
527  * - <tt>default_on_null()</tt>
528  * - <tt>default_on_null(bool on)</tt>
529  *
530  * If the value associated with this key is \c kind::null, should that be treated as the default value? This option is
531  * only considered if a \ref serialization_builder_dsl_ref_member_level_default_value default_value was provided.
532  *
533  * \paragraph serialization_builder_dsl_ref_member_level_encode_if encode_if
534  *
535  * - <tt>encode_if(std::function&lt;bool (const serialization_context&, const TMember&amp;)&gt; check)</tt>
536  *
537  * Only serialize this member if the \a check function returns true.
538  *
539  * \paragraph serialization_builder_dsl_ref_member_level_since since
540  *
541  * - <tt>since(version)</tt>
542  *
543  * Only serialize this member if the \c serialization_context::version is not \c version::empty and is greater than the
544  * provided \c version.
545  *
546  * \paragraph serialization_builder_dsl_ref_member_level_until until
547  *
548  * - <tt>until(version)</tt>
549  *
550  * Only serialize this member if the \c serialization_context::version is not \c version::empty and is less than the
551  * provided \c version.
552 **/
553 
554 class formats_builder;
555 
556 template <typename T> class adapter_builder;
557 template <typename T, typename TMember> class member_adapter_builder;
558 template <typename TPointer> class polymorphic_adapter_builder;
559 
560 namespace detail
561 {
562 
564 {
565 public:
566  explicit formats_builder_dsl(formats_builder* owner) :
567  owner(owner)
568  { }
569 
570  template <typename T>
571  adapter_builder<T> type();
572 
573  template <typename T, typename F>
574  adapter_builder<T> type(F&&);
575 
576  template <typename TEnum>
577  formats_builder& enum_type(std::string enum_name, std::initializer_list<std::pair<TEnum, value>> mapping);
578 
579  template <typename TEnum>
580  formats_builder& enum_type_icase(std::string enum_name, std::initializer_list<std::pair<TEnum, value>> mapping);
581 
582  template <typename TPointer>
583  polymorphic_adapter_builder<TPointer> polymorphic_type(std::string discrimination_key = "");
584 
585  template <typename TPointer, typename F>
586  polymorphic_adapter_builder<TPointer> polymorphic_type(std::string discrimination_key, F&&);
587 
588  template <typename F>
589  formats_builder& extend(F&&);
590 
591  formats_builder& register_adapter(const adapter* p);
592  formats_builder& register_adapter(std::shared_ptr<const adapter> p);
593 
594  formats_builder& reference_type(std::type_index typ);
595  formats_builder& reference_type(std::type_index type, std::type_index from);
596 
597  template <typename TOptional>
598  formats_builder& register_optional();
599 
600  template <typename TContainer>
601  formats_builder& register_container();
602 
603  #if JSONV_COMPILER_SUPPORTS_TEMPLATE_TEMPLATES
604  template <typename T, template <class...> class... TTContainers>
605  formats_builder& register_containers();
606  #endif
607 
608  template <typename TWrapper>
609  formats_builder& register_wrapper();
610 
611  formats_builder& check_references(const formats& other, const std::string& name = "");
612  formats_builder& check_references(const formats::list& others, const std::string& name = "");
613  formats_builder& check_references(const std::string& name = "");
614 
615  formats_builder& on_duplicate_type(duplicate_type_action action) noexcept;
616 
617  formats compose_checked(formats other, const std::string& name = "");
618  formats compose_checked(std::vector<formats> others, const std::string& name = "");
619 
620  operator formats() const;
621 
622 protected:
623  formats_builder* owner;
624 };
625 
626 template <typename T>
628 {
629 public:
630  explicit adapter_builder_dsl(adapter_builder<T>* owner) :
631  owner(owner)
632  { }
633 
634  adapter_builder<T>& type_default_on_null(bool on = true);
635 
636  adapter_builder<T>& type_default_value(std::function<T (const extraction_context& ctx)> create);
637 
638  adapter_builder<T>& type_default_value(const T& value);
639 
640  template <typename TMember>
641  member_adapter_builder<T, TMember> member(std::string name, TMember T::*selector);
642 
643  template <typename TMember>
644  member_adapter_builder<T, TMember> member(std::string name,
645  std::function<const TMember& (const T&)> access,
646  std::function<void (T&, TMember&&)> mutate
647  );
648 
649  template <typename TMember>
650  member_adapter_builder<T, TMember> member(std::string name,
651  const TMember& (T::*access)() const,
652  TMember& (T::*mutable_access)()
653  );
654 
655  template <typename TMember>
656  member_adapter_builder<T, TMember> member(std::string name,
657  const TMember& (T::*access)() const,
658  void (T::*mutate)(TMember)
659  );
660 
661  template <typename TMember>
662  member_adapter_builder<T, TMember> member(std::string name,
663  const TMember& (T::*access)() const,
664  void (T::*mutate)(TMember&&)
665  );
666 
667  adapter_builder<T>& pre_extract(typename adapter_builder<T>::pre_extract_func perform);
668 
669  adapter_builder<T>& post_extract(typename adapter_builder<T>::post_extract_func perform);
670 
671  adapter_builder<T>& on_extract_extra_keys(typename adapter_builder<T>::extra_keys_func handler);
672 
673 protected:
674  adapter_builder<T>* owner;
675 };
676 
677 template <typename T>
679 {
680 public:
681  virtual ~member_adapter() noexcept
682  { }
683 
684  virtual void mutate(const extraction_context& context, const value& from, T& out) const = 0;
685 
686  virtual void to_json(const serialization_context& context, const T& from, value& out) const = 0;
687 
688  virtual bool has_extract_key(string_view key) const = 0;
689 };
690 
691 template <typename T, typename TMember>
693  public member_adapter<T>
694 {
695 public:
696  using mutator_type = std::function<void (T&, TMember&&)>;
697  using accessor_type = std::function<const TMember& (const T&)>;
698 
699 public:
700  explicit member_adapter_impl(std::string name, mutator_type mutator, accessor_type access) :
701  _names({ std::move(name) }),
702  _set_value(std::move(mutator)),
703  _get_value(std::move(access))
704  { }
705 
706  explicit member_adapter_impl(std::string name, TMember T::*selector) :
707  member_adapter_impl(std::move(name),
708  [selector] (T& value, TMember&& x) { value.*selector = std::move(x); },
709  [selector] (const T& value) -> const TMember& { return value.*selector; }
710  )
711  { }
712 
713  virtual void mutate(const extraction_context& context, const value& from, T& out) const override
714  {
716  for (const auto& name : _names)
717  if ((iter = from.find(name)) != from.end_object())
718  break;
719 
720  bool use_default = false;
721  if (iter == from.end_object())
722  {
723  use_default = bool(_default_value);
724  if (!use_default)
725  throw extraction_error(context, std::string("Missing required field ") + _names.at(0));
726  }
727  else if (_default_on_null && iter->second.kind() == kind::null)
728  {
729  use_default = true;
730  }
731 
732  if (use_default)
733  _set_value(out, _default_value(context, from));
734  else
735  _set_value(out, context.extract_sub<TMember>(from, iter->first));
736  }
737 
738  virtual void to_json(const serialization_context& context, const T& from, value& out) const override
739  {
740  if (should_encode(context, from))
741  out.insert({ _names.at(0), context.to_json(_get_value(from)) });
742  }
743 
744  virtual bool has_extract_key(string_view key) const override
745  {
746  return std::any_of(begin(_names), end(_names), [key] (const std::string& name) { return name == key; });
747  }
748 
749  void add_encode_check(std::function<bool (const serialization_context&, const TMember&)> check)
750  {
751  if (_should_encode)
752  {
753  auto old_check = std::move(_should_encode);
754  _should_encode = [check, old_check] (const serialization_context& context, const TMember& value)
755  {
756  return check(context, value) && old_check(context, value);
757  };
758  }
759  else
760  {
761  _should_encode = std::move(check);
762  }
763  }
764 
765  void add_extraction_mutator(std::function <TMember (TMember&&)> mutate)
766  {
767  if (_extract_mutate)
768  {
769  auto old_mutate = std::move(_extract_mutate);
770  _extract_mutate = [old_mutate, mutate] (TMember&& member) { return mutate(old_mutate(std::move(member))); };
771  }
772  else
773  {
774  _extract_mutate = std::move(mutate);
775  }
776  }
777 
778  void add_extraction_check(std::function <void (const TMember&)> check)
779  {
780  add_extraction_mutator([check] (TMember&& value)
781  {
782  check(value);
783  return value;
784  });
785  }
786 
787  void default_value(std::function<TMember (const extraction_context&, const value&)>&& create)
788  {
789  _default_value = std::move(create);
790  }
791 
792  void default_on_null(bool on)
793  {
794  _default_on_null = on;
795  }
796 
797 private:
798  bool should_encode(const serialization_context& context, const T& from) const
799  {
800  if (_should_encode)
801  return _should_encode(context, _get_value(from));
802  else
803  return true;
804  }
805 
806 private:
807  template <typename U, typename UMember>
808  friend class member_adapter_builder;
809 
810 private:
811  std::vector<std::string> _names;
812  mutator_type _set_value;
813  accessor_type _get_value;
814  std::function<bool (const serialization_context&, const TMember&)> _should_encode;
815  std::function<TMember (const extraction_context&, const value&)> _default_value;
816  bool _default_on_null = false;
817  std::function<TMember (TMember&&)> _extract_mutate;
818 };
819 
820 }
821 
822 template <typename T, typename TMember>
826 {
827 public:
828  explicit member_adapter_builder(formats_builder* fmt_builder,
829  adapter_builder<T>* adapt_builder,
831  ) :
832  formats_builder_dsl(fmt_builder),
833  detail::adapter_builder_dsl<T>(adapt_builder),
834  _adapter(adapter)
835  {
836  reference_type(std::type_index(typeid(TMember)), std::type_index(typeid(T)));
837  }
838 
839  /** When extracting, also look for this \a name as a key. **/
841  {
842  _adapter->_names.emplace_back(std::move(name));
843  return *this;
844  }
845 
846  member_adapter_builder& check_input(std::function<void (const TMember&)> check)
847  {
848  _adapter->add_extraction_check(std::move(check));
849  return *this;
850  }
851 
852  member_adapter_builder& check_input(std::function<bool (const TMember&)> check,
853  std::function<void (const TMember&)> thrower
854  )
855  {
856  _adapter->add_extraction_check([check, thrower] (const TMember& value)
857  {
858  if (!check(value))
859  thrower(value);
860  });
861  return *this;
862  }
863 
864  template <typename TException>
865  member_adapter_builder& check_input(std::function<void (const TMember&)> check, const TException& ex)
866  {
867  return check_input(std::move(check), [ex] (const TMember&) { throw ex; });
868  }
869 
870  /** If the key for this member is not in the object when deserializing, call this function to create a value. If a
871  * \c default_value is not specified, the key is required.
872  **/
873  member_adapter_builder& default_value(std::function<TMember (const extraction_context&, const value&)> create)
874  {
875  _adapter->default_value(std::move(create));
876  return *this;
877  }
878 
879  /** If the key for this member is not in the object when deserializing, use this \a value. If a \c default_value is
880  * not specified, the key is required.
881  **/
883  {
884  return default_value([value] (const extraction_context&, const jsonv::value&) { return value; });
885  }
886 
887  /** Should a \c kind::null for a key be interpreted as a missing value? **/
889  {
890  _adapter->default_on_null(on);
891  return *this;
892  }
893 
894  /** Only encode this member if the \a check passes. The final decision to encode is based on \e all \c check
895  * functions.
896  **/
897  member_adapter_builder& encode_if(std::function<bool (const serialization_context&, const TMember&)> check)
898  {
899  _adapter->add_encode_check(std::move(check));
900  return *this;
901  }
902 
903  /** Only encode this member if the \c serialization_context::version is greater than or equal to \a ver. **/
905  {
906  return encode_if([ver] (const serialization_context& context, const TMember&)
907  {
908  return context.version().empty() || context.version() >= ver;
909  }
910  );
911  }
912 
913  /** Only encode this member if the \c serialization_context::version is less than or equal to \a ver. **/
915  {
916  return encode_if([ver] (const serialization_context& context, const TMember&)
917  {
918  return context.version().empty() || context.version() <= ver;
919  }
920  );
921  }
922 
923  /** Only encode this member if the \c serialization_context::version is greater than \a ver. **/
925  {
926  return encode_if([ver] (const serialization_context& context, const TMember&)
927  {
928  return context.version().empty() || context.version() > ver;
929  }
930  );
931  }
932 
933  /** Only encode this member if the \c serialization_context::version is less than \a ver. **/
935  {
936  return encode_if([ver] (const serialization_context& context, const TMember&)
937  {
938  return context.version().empty() || context.version() < ver;
939  }
940  );
941  }
942 
943 private:
945 };
946 
947 template <typename T>
948 class adapter_builder :
950 {
951 public:
952  using pre_extract_func = std::function<void (const extraction_context&, const value&)>;
953  using post_extract_func = std::function<T (const extraction_context&, T&&)>;
954  using extra_keys_func = std::function<void (const extraction_context&, const value&, std::set<std::string>)>;
955 
956 public:
957  template <typename F>
958  explicit adapter_builder(formats_builder* owner, F&& f) :
959  formats_builder_dsl(owner),
960  _adapter(nullptr)
961  {
962  auto adapter = std::make_shared<adapter_impl>();
963  register_adapter(adapter);
964  _adapter = adapter.get();
965 
966  std::forward<F>(f)(*this);
967  }
968 
969  explicit adapter_builder(formats_builder* owner) :
970  adapter_builder(owner, [] (const adapter_builder<T>&) { })
971  { }
972 
973  adapter_builder<T>& type_default_on_null(bool on = true)
974  {
975  _adapter->_default_on_null = on;
976  return *this;
977  }
978 
979  adapter_builder<T>& type_default_value(std::function<T (const extraction_context& ctx)> create)
980  {
981  _adapter->_create_default = std::move(create);
982  return *this;
983  }
984 
985  adapter_builder<T>& type_default_value(const T& value)
986  {
987  return type_default_value([value] (const extraction_context&) { return T(value); });
988  }
989 
990  template <typename TMember>
991  member_adapter_builder<T, TMember> member(std::string name, TMember T::*selector)
992  {
993  std::unique_ptr<detail::member_adapter_impl<T, TMember>> ptr
994  (
995  new detail::member_adapter_impl<T, TMember>(std::move(name), selector)
996  );
997  member_adapter_builder<T, TMember> builder(formats_builder_dsl::owner, this, ptr.get());
998  _adapter->_members.emplace_back(std::move(ptr));
999  return builder;
1000  }
1001 
1002  template <typename TMember>
1003  member_adapter_builder<T, TMember> member(std::string name,
1004  std::function<const TMember& (const T&)> access,
1005  std::function<void (T&, TMember&&)> mutate
1006  )
1007  {
1008  std::unique_ptr<detail::member_adapter_impl<T, TMember>> ptr
1009  (
1010  new detail::member_adapter_impl<T, TMember>(std::move(name), std::move(mutate), std::move(access))
1011  );
1012  member_adapter_builder<T, TMember> builder(formats_builder_dsl::owner, this, ptr.get());
1013  _adapter->_members.emplace_back(std::move(ptr));
1014  return builder;
1015  }
1016 
1017  template <typename TMember>
1018  member_adapter_builder<T, TMember> member(std::string name,
1019  const TMember& (T::*access)() const,
1020  TMember& (T::*mutable_access)()
1021  )
1022  {
1023  return member<TMember>(std::move(name),
1024  access,
1025  [mutable_access] (T& x, TMember&& val) { (x.*mutable_access)() = std::move(val); }
1026  );
1027  }
1028 
1029  template <typename TMember>
1030  member_adapter_builder<T, TMember> member(std::string name,
1031  const TMember& (T::*access)() const,
1032  void (T::*mutate)(TMember)
1033  )
1034  {
1035  return member<TMember>(std::move(name),
1036  std::function<const TMember& (const T&)>(access),
1037  [mutate] (T& x, TMember val) { (x.*mutate)(std::move(val)); }
1038  );
1039  }
1040 
1041  template <typename TMember>
1042  member_adapter_builder<T, TMember> member(std::string name,
1043  const TMember& (T::*access)() const,
1044  void (T::*mutate)(TMember&&)
1045  )
1046  {
1047  return member<TMember>(std::move(name),
1048  std::function<const TMember& (const T&)>(access),
1049  std::function<void (T&, TMember&&)>(mutate)
1050  );
1051  }
1052 
1053  adapter_builder<T>& pre_extract(pre_extract_func perform)
1054  {
1055  if (_adapter->_pre_extract)
1056  {
1057  pre_extract_func old_perform = std::move(_adapter->_pre_extract);
1058  _adapter->_pre_extract = [old_perform, perform] (const extraction_context& context, const value& from)
1059  {
1060  old_perform(context, from);
1061  perform(context, from);
1062  };
1063  }
1064  else
1065  {
1066  _adapter->_pre_extract = std::move(perform);
1067  }
1068  return *this;
1069  }
1070 
1071  adapter_builder<T>& post_extract(post_extract_func perform)
1072  {
1073  if (_adapter->_post_extract)
1074  {
1075  post_extract_func old_perform = std::move(_adapter->_post_extract);
1076  _adapter->_post_extract = [old_perform, perform] (const extraction_context& context, T&& out)
1077  {
1078  return perform(context, old_perform(context, std::move(out)));
1079  };
1080  }
1081  else
1082  {
1083  _adapter->_post_extract = std::move(perform);
1084  }
1085  return *this;
1086  }
1087 
1088  adapter_builder<T>& on_extract_extra_keys(extra_keys_func handler)
1089  {
1090  adapter_impl* adapter = _adapter;
1091  return pre_extract([adapter, handler] (const extraction_context& context, const value& from)
1092  {
1093  auto is_key = [adapter] (string_view key) -> bool
1094  {
1095  return std::any_of(begin(adapter->_members), end(adapter->_members),
1096  [key] (const std::unique_ptr<detail::member_adapter<T>>& mem)
1097  {
1098  return mem->has_extract_key(key);
1099  }
1100  );
1101  };
1102  std::set<std::string> extra_keys;
1103  for (const auto& pair : from.as_object())
1104  if (!is_key(pair.first))
1105  extra_keys.insert(pair.first);
1106  if (!extra_keys.empty())
1107  handler(context, from, std::move(extra_keys));
1108  });
1109  }
1110 
1111 private:
1112  class adapter_impl :
1113  public adapter_for<T>
1114  {
1115  public:
1116  adapter_impl() :
1117  _default_on_null(false)
1118  { }
1119 
1120  virtual T create(const extraction_context& context, const value& from) const override
1121  {
1122  if (_pre_extract)
1123  _pre_extract(context, from);
1124 
1125  if (_default_on_null && from.is_null())
1126  return _create_default(context);
1127 
1128  T out;
1129  for (const auto& member : _members)
1130  member->mutate(context, from, out);
1131 
1132  if (_post_extract)
1133  out = _post_extract(context, std::move(out));
1134 
1135  return out;
1136  }
1137 
1138  virtual value to_json(const serialization_context& context, const T& from) const override
1139  {
1140  value out = object();
1141  for (const auto& member : _members)
1142  member->to_json(context, from, out);
1143  return out;
1144  }
1145 
1146  std::deque<std::unique_ptr<detail::member_adapter<T>>> _members;
1147  pre_extract_func _pre_extract;
1148  post_extract_func _post_extract;
1149  std::function<T (const extraction_context&)> _create_default;
1150  bool _default_on_null;
1151  };
1152 
1153 private:
1154  adapter_impl* _adapter;
1155 };
1156 
1157 template <typename TPointer>
1160 {
1161 public:
1162  template <typename F>
1164  std::string discrimination_key,
1165  F&& f
1166  ) :
1167  formats_builder_dsl(owner),
1168  _adapter(nullptr),
1169  _discrimination_key(std::move(discrimination_key))
1170  {
1171  auto adapter = std::make_shared<polymorphic_adapter<TPointer>>();
1172  register_adapter(adapter);
1173  _adapter = adapter.get();
1174 
1175  std::forward<F>(f)(*this);
1176  }
1177 
1178  explicit polymorphic_adapter_builder(formats_builder* owner, std::string discrimination_key = "") :
1180  std::move(discrimination_key),
1182  )
1183  { }
1184 
1185  polymorphic_adapter_builder& check_null_input(bool on = true)
1186  {
1187  _adapter->check_null_input(on);
1188  return *this;
1189  }
1190 
1191  polymorphic_adapter_builder& check_null_output(bool on = true)
1192  {
1193  _adapter->check_null_output(on);
1194  return *this;
1195  }
1196 
1197  template <typename TSub>
1198  polymorphic_adapter_builder& subtype(value discrimination_value,
1200  {
1201  if (_discrimination_key.empty())
1202  throw std::logic_error("Cannot use single-argument subtype if no discrimination_key has been set");
1203 
1204  return subtype<TSub>(_discrimination_key, std::move(discrimination_value), action);
1205  }
1206 
1207  template <typename TSub>
1208  polymorphic_adapter_builder& subtype(std::string discrimination_key,
1209  value discrimination_value,
1211  {
1212  _adapter->template add_subtype_keyed<TSub>(std::move(discrimination_key),
1213  std::move(discrimination_value),
1214  action);
1215  reference_type(std::type_index(typeid(TSub)), std::type_index(typeid(TPointer)));
1216  return *this;
1217  }
1218 
1219  template <typename TSub>
1220  polymorphic_adapter_builder& subtype(std::function<bool (const extraction_context&, const value&)> discriminator)
1221  {
1222  _adapter->template add_subtype<TSub>(std::move(discriminator));
1223  reference_type(std::type_index(typeid(TSub)), std::type_index(typeid(TPointer)));
1224  return *this;
1225  }
1226 
1227  template <typename TSub>
1228  polymorphic_adapter_builder& subtype(std::function<bool (const value&)> discriminator)
1229  {
1230  return subtype<TSub>([discriminator] (const extraction_context&, const value& val)
1231  {
1232  return discriminator(val);
1233  }
1234  );
1235  }
1236 
1237 private:
1239  std::string _discrimination_key;
1240 };
1241 
1243 {
1244 public:
1245  formats_builder();
1246 
1247  template <typename T>
1248  adapter_builder<T> type()
1249  {
1250  return adapter_builder<T>(this);
1251  }
1252 
1253  template <typename T, typename F>
1254  adapter_builder<T> type(F&& f)
1255  {
1256  return adapter_builder<T>(this, std::forward<F>(f));
1257  }
1258 
1259  template <typename TEnum>
1260  formats_builder& enum_type(std::string enum_name,
1261  std::initializer_list<std::pair<TEnum, value>> mapping
1262  )
1263  {
1264  return register_adapter(std::make_shared<enum_adapter<TEnum>>(std::move(enum_name), mapping));
1265  }
1266 
1267  template <typename TEnum>
1268  formats_builder& enum_type_icase(std::string enum_name,
1269  std::initializer_list<std::pair<TEnum, value>> mapping
1270  )
1271  {
1272  return register_adapter(std::make_shared<enum_adapter_icase<TEnum>>(std::move(enum_name), mapping));
1273  }
1274 
1275  template <typename TPointer>
1277  polymorphic_type(std::string discrimination_key = "")
1278  {
1279  return polymorphic_adapter_builder<TPointer>(this, std::move(discrimination_key));
1280  }
1281 
1282  template <typename TPointer, typename F>
1284  polymorphic_type(std::string discrimination_key, F&& f)
1285  {
1286  return polymorphic_adapter_builder<TPointer>(this, std::move(discrimination_key), std::forward<F>(f));
1287  }
1288 
1289  template <typename F>
1290  formats_builder& extend(F&& func)
1291  {
1292  std::forward<F>(func)(*this);
1293  return *this;
1294  }
1295 
1296  formats_builder& register_adapter(const adapter* p)
1297  {
1298  _formats.register_adapter(p, _duplicate_type_action);
1299  return *this;
1300  }
1301 
1302  formats_builder& register_adapter(std::shared_ptr<const adapter> p)
1303  {
1304  _formats.register_adapter(std::move(p), _duplicate_type_action);
1305  return *this;
1306  }
1307 
1308  template <typename TOptional>
1309  formats_builder& register_optional()
1310  {
1311  reference_type(std::type_index(typeid(typename TOptional::value_type)), std::type_index(typeid(TOptional)));
1312  std::unique_ptr<optional_adapter<TOptional>> p(new optional_adapter<TOptional>);
1313  _formats.register_adapter(std::move(p), _duplicate_type_action);
1314  return *this;
1315  }
1316 
1317  template <typename TContainer>
1318  formats_builder& register_container()
1319  {
1320  reference_type(std::type_index(typeid(typename TContainer::value_type)), std::type_index(typeid(TContainer)));
1321  std::unique_ptr<container_adapter<TContainer>> p(new container_adapter<TContainer>);
1322  _formats.register_adapter(std::move(p), _duplicate_type_action);
1323  return *this;
1324  }
1325 
1326  template <typename TWrapper>
1327  formats_builder& register_wrapper()
1328  {
1329  reference_type(std::type_index(typeid(typename TWrapper::value_type)), std::type_index(typeid(TWrapper)));
1330  std::unique_ptr<wrapper_adapter<TWrapper>> p(new wrapper_adapter<TWrapper>);
1331  _formats.register_adapter(std::move(p), _duplicate_type_action);
1332  return *this;
1333  }
1334 
1335  #if JSONV_COMPILER_SUPPORTS_TEMPLATE_TEMPLATES
1336  template <typename T>
1337  formats_builder& register_containers()
1338  {
1339  return *this;
1340  }
1341 
1342  template <typename T, template <class...> class TTContainer, template <class...> class... TTRest>
1343  formats_builder& register_containers()
1344  {
1345  register_container<TTContainer<T>>();
1346  return register_containers<T, TTRest...>();
1347  }
1348  #endif
1349 
1350  operator formats() const
1351  {
1352  return _formats;
1353  }
1354 
1355  formats_builder& reference_type(std::type_index type);
1356  formats_builder& reference_type(std::type_index type, std::type_index from);
1357 
1358  /// \{
1359  /// Check that, when combined with the \c formats \a other, all types referenced by this \c formats_builder will
1360  /// get decoded properly.
1361  ///
1362  /// \param name if non-empty and this function throws, this \a name will be provided in the exception's \c what
1363  /// string. This can be useful if you are running multiple \c check_references calls and you want to
1364  /// name the different checks.
1365  ///
1366  /// \throws std::logic_error if \c formats this \c formats_builder is generating, when combined with the provided
1367  /// \a other \c formats, cannot properly serialize all the types.
1368  formats_builder& check_references(const formats& other, const std::string& name = "");
1369  formats_builder& check_references(const formats::list& others, const std::string& name = "");
1370  formats_builder& check_references(const std::string& name = "");
1371  /// \}
1372 
1373  /// \{
1374  /// Check the references of this builder (see \ref check_references) and compose a \ref formats instance if
1375  /// successful (see \ref formats::compose).
1376  formats compose_checked(formats other, const std::string& name = "");
1377  formats compose_checked(const formats::list& others, const std::string& name = "");
1378  /// \}
1379 
1380  /** Assigns the action to perform when a serializer or extractor is being registered by this formats_builder and
1381  * there is already a serializer or extracter for that type.
1382  **/
1383  formats_builder& on_duplicate_type(duplicate_type_action action) noexcept;
1384 
1385 private:
1386  void check_references_impl(const formats& searching, const std::string& name);
1387 
1388 private:
1389  formats _formats;
1391  std::map<std::type_index, std::set<std::type_index>> _referenced_types;
1392 };
1393 
1394 namespace detail
1395 {
1396 
1397 template <typename T>
1398 adapter_builder<T> formats_builder_dsl::type()
1399 {
1400  return owner->type<T>();
1401 }
1402 
1403 template <typename T, typename F>
1404 adapter_builder<T> formats_builder_dsl::type(F&& f)
1405 {
1406  return owner->type<T>(std::forward<F>(f));
1407 }
1408 
1409 template <typename TEnum>
1410 formats_builder& formats_builder_dsl::enum_type(std::string enum_name,
1411  std::initializer_list<std::pair<TEnum, value>> mapping
1412  )
1413 {
1414  return owner->enum_type<TEnum>(std::move(enum_name), mapping);
1415 }
1416 
1417 template <typename TEnum>
1418 formats_builder& formats_builder_dsl::enum_type_icase(std::string enum_name,
1419  std::initializer_list<std::pair<TEnum, value>> mapping
1420  )
1421 {
1422  return owner->enum_type_icase<TEnum>(std::move(enum_name), mapping);
1423 }
1424 
1425 template <typename TPointer>
1427 formats_builder_dsl::polymorphic_type(std::string discrimination_key)
1428 {
1429  return owner->polymorphic_type<TPointer>(std::move(discrimination_key));
1430 }
1431 
1432 template <typename TPointer, typename F>
1434 formats_builder_dsl::polymorphic_type(std::string discrimination_key, F&& f)
1435 {
1436  return owner->polymorphic_type<TPointer>(std::move(discrimination_key), std::forward<F>(f));
1437 }
1438 
1439 template <typename F>
1440 formats_builder& formats_builder_dsl::extend(F&& f)
1441 {
1442  return owner->extend(std::forward<F>(f));
1443 }
1444 
1445 template <typename TOptional>
1446 formats_builder& formats_builder_dsl::register_optional()
1447 {
1448  return owner->register_optional<TOptional>();
1449 }
1450 
1451 template <typename TContainer>
1452 formats_builder& formats_builder_dsl::register_container()
1453 {
1454  return owner->register_container<TContainer>();
1455 }
1456 
1457 #if JSONV_COMPILER_SUPPORTS_TEMPLATE_TEMPLATES
1458 template <typename T, template <class...> class... TTContainers>
1459 formats_builder& formats_builder_dsl::register_containers()
1460 {
1461  return owner->register_containers<T, TTContainers...>();
1462 }
1463 #endif
1464 
1465 template <typename TWrapper>
1466 formats_builder& formats_builder_dsl::register_wrapper()
1467 {
1468  return owner->register_container<TWrapper>();
1469 }
1470 
1471 template <typename T>
1472 adapter_builder<T>& adapter_builder_dsl<T>::type_default_on_null(bool on)
1473 {
1474  return owner->type_default_on_null(on);
1475 }
1476 
1477 template <typename T>
1478 adapter_builder<T>& adapter_builder_dsl<T>::type_default_value(std::function<T (const extraction_context& ctx)> create)
1479 {
1480  return owner->type_default_value(std::move(create));
1481 }
1482 
1483 template <typename T>
1484 adapter_builder<T>& adapter_builder_dsl<T>::type_default_value(const T& value)
1485 {
1486  return owner->type_default_value(value);
1487 }
1488 
1489 template <typename T>
1490 template <typename TMember>
1491 member_adapter_builder<T, TMember> adapter_builder_dsl<T>::member(std::string name, TMember T::*selector)
1492 {
1493  return owner->member(std::move(name), selector);
1494 }
1495 
1496 template <typename T>
1497 template <typename TMember>
1499 adapter_builder_dsl<T>::member(std::string name,
1500  std::function<const TMember& (const T&)> access,
1501  std::function<void (T&, TMember&&)> mutate
1502  )
1503 {
1504  return owner->member(std::move(name), std::move(access), std::move(mutate));
1505 }
1506 
1507 template <typename T>
1508 template <typename TMember>
1510 adapter_builder_dsl<T>::member(std::string name,
1511  const TMember& (T::*access)() const,
1512  TMember& (T::*mutable_access)()
1513  )
1514 {
1515  return owner->member(std::move(name), access, mutable_access);
1516 }
1517 
1518 template <typename T>
1519 template <typename TMember>
1521 adapter_builder_dsl<T>::member(std::string name,
1522  const TMember& (T::*access)() const,
1523  void (T::*mutate)(TMember)
1524  )
1525 {
1526  return owner->member(std::move(name), access, mutate);
1527 }
1528 
1529 template <typename T>
1530 template <typename TMember>
1532 adapter_builder_dsl<T>::member(std::string name,
1533  const TMember& (T::*access)() const,
1534  void (T::*mutate)(TMember&&)
1535  )
1536 {
1537  return owner->member(std::move(name), access, mutate);
1538 }
1539 
1540 template <typename T>
1541 adapter_builder<T>& adapter_builder_dsl<T>::pre_extract(typename adapter_builder<T>::pre_extract_func perform)
1542 {
1543  return owner->pre_extract(std::move(perform));
1544 }
1545 
1546 template <typename T>
1547 adapter_builder<T>& adapter_builder_dsl<T>::post_extract(typename adapter_builder<T>::post_extract_func perform)
1548 {
1549  return owner->post_extract(std::move(perform));
1550 }
1551 
1552 template <typename T>
1553 adapter_builder<T>& adapter_builder_dsl<T>::on_extract_extra_keys(typename adapter_builder<T>::extra_keys_func handler)
1554 {
1555  return owner->on_extract_extra_keys(std::move(handler));
1556 }
1557 
1558 }
1559 
1560 /** Throw an \a extraction_error indicating that \a from had extra keys.
1561  *
1562  * \throws extraction_error always.
1563 **/
1566  const value& from,
1567  const std::set<std::string>& extra_keys
1568  );
1569 
1570 }
1571 
1572 #endif/*__JSONV_SERIALIZATION_BUILDER_HPP_INCLUDED__*/
#define JSONV_NO_RETURN
Mark that a given function will never return control to the caller, either by exiting or throwing an ...
Definition: config.hpp:127
An adapter for container types.
object_iterator end_object()
Get an iterator to the one past the end of this object.
member_adapter_builder & default_on_null(bool on=true)
Should a kind::null for a key be interpreted as a missing value?
T extract_sub(const value &from, jsonv::path subpath) const
Attempt to extract a T from from.at_path(subpath) using the formats associated with this context...
Don&#39;t do any checking or insertion of the expected key/value pair.
A duplicate_type_error should be thrown.
member_adapter_builder & after(version ver)
Only encode this member if the serialization_context::version is greater than ver.
array_iterator insert(const_array_iterator position, value item)
Insert an item into position on this array.
Exception thrown if there is any problem running extract.
bool is_null() const
Tests if this kind is kind::null.
JSONV_PUBLIC JSONV_NO_RETURN void throw_extra_keys_extraction_error(const extraction_context &context, const value &from, const std::set< std::string > &extra_keys)
Throw an extraction_error indicating that from had extra keys.
Helper types and functions for serialization.
member_adapter_builder & encode_if(std::function< bool(const serialization_context &, const TMember &)> check)
Only encode this member if the check passes.
Copyright (c) 2014-2019 by Travis Gockel.
object_view as_object()&
View this instance as an object.
An adapter is both an extractor and a serializer.
constexpr bool empty() const
Check if this version is an "empty" value – meaning major and minor are both 0.
An adapter for optional-like types.
An adapter which can create polymorphic types.
object_iterator find(const std::string &key)
Attempt to locate a key-value pair with the provided key in this object.
member_adapter_builder & before(version ver)
Only encode this member if the serialization_context::version is less than ver.
Simply put, this class is a collection of extractor and serializer instances.
member_adapter_builder & default_value(std::function< TMember(const extraction_context &, const value &)> create)
If the key for this member is not in the object when deserializing, call this function to create a va...
const jsonv::version version() const
Get the version this extraction_context was created with.
member_adapter_builder & since(version ver)
Only encode this member if the serialization_context::version is greater than or equal to ver...
member_adapter_builder & default_value(TMember value)
If the key for this member is not in the object when deserializing, use this value.
keyed_subtype_action
What to do when serializing a keyed subtype of a polymorphic_adapter.
An adapter for enumeration types.
Conversion between C++ types and JSON values.
member_adapter_builder & alternate_name(std::string name)
When extracting, also look for this name as a key.
An adapter for "wrapper" types.
Represents a version used to extract and encode JSON objects from C++ classes.
JSONV_PUBLIC value object()
Create an empty object.
Ensure the correct key/value pair was inserted by serialization.
value to_json(const T &from, const formats &fmts)
Encode a JSON value from from using the provided fmts.
value to_json(const T &from) const
Convenience function for converting a C++ object into a JSON value.
A non-owning reference to an std::string, as proposed to the C++ Standard Committee by Jeffrey Yasski...
Definition: string_view.hpp:34
#define JSONV_PUBLIC
This function or class is part of the public API for JsonVoorhees.
Definition: config.hpp:104
member_adapter_builder & until(version ver)
Only encode this member if the serialization_context::version is less than or equal to ver...
JSONV_STRING_VIEW_TYPE string_view
A non-owning reference to a string.
Definition: string_view.hpp:52
Represents a single JSON value, which can be any one of a potential kind, each behaving slightly diff...
Definition: value.hpp:131
duplicate_type_action
The action to take when an insertion of an extractor or serializer into a formats is attempted...