JSON Voorhees
Killer JSON for C++
Loading...
Searching...
No Matches
serialization.hpp
Go to the documentation of this file.
1/// \file jsonv/serialization.hpp
2/// Conversion between C++ types and JSON values.
3///
4/// Copyright (c) 2015-2020 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#pragma once
12
13#include <jsonv/config.hpp>
15#include <jsonv/path.hpp>
16#include <jsonv/value.hpp>
17#include <jsonv/version.hpp>
18
19#include <exception>
20#include <memory>
21#include <new>
22#include <typeinfo>
23#include <typeindex>
24#include <type_traits>
25#include <utility>
26#include <vector>
27
28namespace jsonv
29{
30
31/// \addtogroup Serialization
32/// \{
33/// Serialization components are responsible for conversion between a C++ type and a JSON \c value.
34
35class extractor;
36class value;
37class extraction_context;
38class serialization_context;
39
40/// The action to take when an insertion of an extractor or serializer into a formats is attempted, but there is alredy
41/// an extractor or serializer for that type.
42enum class duplicate_type_action : unsigned char
43{
44 /// The existing extractor or serializer should be kept, but no exception should be thrown.
45 ignore,
46 /// The new extractor or serializer should be inserted, and no exception should be thrown.
47 replace,
48 /// A \ref duplicate_type_error should be thrown.
50};
51
52/// Exception thrown if an insertion of an extractor or serializer into a formats is attempted, but there is already an
53/// extractor or serializer for that type.
55 public std::invalid_argument
56{
57public:
58 explicit duplicate_type_error(const std::string& operation, const std::type_index& type);
59
60 virtual ~duplicate_type_error() noexcept override;
61
62 const std::type_index& type_index() const { return _type_index; }
63
64private:
65 std::type_index _type_index;
66};
67
68/// Exception thrown if there is any problem running \c extract.
70 public std::runtime_error
71{
72public:
73 /// Description of a single problem with extraction.
74 class problem
75 {
76 public:
77 /// \{
78 /// Create a problem for the given \a path, \a message, and optional \a cause.
79 explicit problem(jsonv::path path, std::string message, std::exception_ptr cause) noexcept;
80 explicit problem(jsonv::path path, std::string message) noexcept;
81 /// \}
82
83 /// Create a problem with a \c message extracted from \a cause.
84 ///
85 /// \param cause The underlying cause of this problem to extract the message from. If the exception backing
86 /// \a cause is not derived from \c std::exception, a message about unknown exception will be used
87 /// instead.
88 explicit problem(jsonv::path path, std::exception_ptr cause) noexcept;
89
90 /// The path this problem was encountered at.
92 {
93 return _path;
94 }
95
96 /// Human-readable details about the encountered problem.
97 const std::string& message() const noexcept
98 {
99 return _message;
100 }
101
102 /// If there was an exception that caused this problem, extra details can be found in the nested exception. This
103 /// can be \c nullptr if there was no underlying cause.
104 const std::exception_ptr& nested_ptr() const noexcept
105 {
106 return _cause;
107 }
108
109 private:
110 jsonv::path _path;
111 std::string _message;
112 std::exception_ptr _cause;
113 };
114
115 using problem_list = std::vector<problem>;
116
117public:
118 /// Create an \c extraction_error from the given list of \a problems.
119 ///
120 /// \param problems The list of problems which caused this error. It is expected that \c problems.size() is greater
121 /// than \c 0. If it is not, a single \c problem will be created with a note about an unspecified
122 /// error.
123 explicit extraction_error(problem_list problems) noexcept;
124
125 /// \{
126 /// Create a new \c extraction_error with a single \c problem from the given \a path, \a message, and optional
127 /// underlying \a cause.
128 explicit extraction_error(jsonv::path path, std::string message, std::exception_ptr cause) noexcept;
129 explicit extraction_error(jsonv::path path, std::string message) noexcept;
130 explicit extraction_error(jsonv::path path, std::exception_ptr cause) noexcept;
131 /// \}
132
133 virtual ~extraction_error() noexcept;
134
135 /// Get the path the first extraction error came from.
137
138 /// Get the first \c problem::cause. This can be \c nullptr if the first \c problem does not have an underlying
139 /// cause.
141
142 /// Get the list of problems which caused this \c extraction_error. There will always be at least one \c problem in
143 /// this list.
144 const problem_list& problems() const noexcept { return _problems; }
145
146private:
147 template <typename... TArgs>
148 explicit extraction_error(std::in_place_t, TArgs&&... problem_args) noexcept;
149
150private:
151 problem_list _problems;
152};
153
154/// Thrown when \c formats::extract does not have an \c extractor for the provided type.
156 public std::runtime_error
157{
158public:
159 /// \{
160 /// Create a new exception.
161 explicit no_extractor(const std::type_info& type);
162 explicit no_extractor(const std::type_index& type);
163 /// \}
164
165 virtual ~no_extractor() noexcept;
166
167 /// The name of the type.
168 string_view type_name() const;
169
170 /// Get an ID for the type of \c extractor that \c formats::extract could not locate.
171 std::type_index type_index() const;
172
173private:
174 std::type_index _type_index;
175 std::string _type_name;
176};
177
178/** Thrown when \c formats::to_json does not have a \c serializer for the provided type. **/
180 public std::runtime_error
181{
182public:
183 /** Create a new exception. **/
184 explicit no_serializer(const std::type_info& type);
185 explicit no_serializer(const std::type_index& type);
186
187 virtual ~no_serializer() noexcept;
188
189 /** The name of the type. **/
190 string_view type_name() const;
191
192 /** Get an ID for the type of \c serializer that \c formats::to_json could not locate. **/
193 std::type_index type_index() const;
194
195private:
196 std::type_index _type_index;
197 std::string _type_name;
198};
199
200/// Configuration for various extraction options. This becomes part of the \c extraction_context.
202{
203public:
204 using size_type = extraction_error::problem_list::size_type;
205
206 /// When an error is encountered during extraction, what should happen?
207 enum class on_error
208 {
209 /// Immediately throw an \c extraction_error -- do not attempt to continue.
210 fail_immediately,
211 /// Attempt to continue extraction, collecting all errors and throwing at the end.
212 collect_all,
213 };
214
215 /// When an object key has the same value as a previously-seen key, what should happen?
217 {
218 /// Replace the previous value with the new one. The final value of the key in the object will be the
219 /// last-encountered one.
220 ///
221 /// For example: `{ "a": 1, "a": 2, "a": 3 }` will end with `{ "a": 3 }`.
222 replace,
223 /// Ignore the new values. The final value of the key in the object will be the first-encountered one.
224 ///
225 /// For example: `{ "a": 1, "a": 2, "a": 3 }` will end with `{ "a": 1 }`.
226 ignore,
227 /// Repeated keys should raise an \c extraction_error.
228 exception,
229 };
230
231public:
232 /// Create an instance with the default options.
234
236
237 /// Create a default set of options.
238 static extract_options create_default();
239
240 /// \{
241 /// See \c on_error. The default failure mode is \c fail_immediately.
242 on_error failure_mode() const noexcept { return _failure_mode; };
243 extract_options& failure_mode(on_error mode);
244 /// \}
245
246 /// \{
247 /// The maximum allowed extractor failures the parser can encounter before throwing an error. This is only
248 /// applicable if the \c failure_mode is not \c on_error::fail_immediately. By default, this value is 10.
249 ///
250 /// You should probably not set this value to an unreasonably high number, as each error encountered must be stored
251 /// in memory for some period of time.
252 size_type max_failures() const { return _max_failures; }
253 extract_options& max_failures(size_type limit);
254 /// \}
255
256 /// \{
257 /// See \c duplicate_key_action. The default action is \c replace.
258 duplicate_key_action on_duplicate_key() const { return _on_duplicate_key; }
259 extract_options& on_duplicate_key(duplicate_key_action action);
260 /// \}
261
262private:
263 // For the purposes of ABI compliance, most modifications to the variables in this class should bump the minor
264 // version number.
265 on_error _failure_mode = on_error::fail_immediately;
266 size_type _max_failures = 10U;
267 duplicate_key_action _on_duplicate_key = duplicate_key_action::replace;
268};
269
270/// An \c extractor holds the method for converting JSON source into an arbitrary C++ type.
272{
273public:
274 virtual ~extractor() noexcept;
275
276 /// Get the run-time type this \c extractor knows how to extract. Once this \c extractor is registered with a
277 /// \c formats, it is not allowed to change.
278 virtual const std::type_info& get_type() const = 0;
279
280 /// Extract a the type \a from a \c value \a into a region of memory.
281 ///
282 /// \param context Extra information to help you decode sub-objects, such as looking up other \c formats. It also
283 /// tracks your \c path in the decoding heirarchy, so any exceptions thrown will have \c path
284 /// information in the error message.
285 /// \param from The JSON \c value to extract something from.
286 /// \param into The region of memory to create the extracted object in. There will always be enough room to create
287 /// your object and the alignment of the pointer should be correct (assuming a working \c alignof
288 /// implementation).
289 virtual void extract(const extraction_context& context,
290 const value& from,
291 void* into
292 ) const = 0;
293};
294
295/** A \c serializer holds the method for converting an arbitrary C++ type into a \c value. **/
297{
298public:
299 virtual ~serializer() noexcept;
300
301 /** Get the run-time type this \c serialize knows how to encode. Once this \c serializer is registered with a
302 * \c formats, it is not allowed to change.
303 **/
304 virtual const std::type_info& get_type() const = 0;
305
306 /** Create a \c value \a from the value in the given region of memory.
307 *
308 * \param context Extra information to help you encode sub-objects for your type, such as the ability to find other
309 * \c formats. It also tracks the progression of types in the encoding heirarchy, so any exceptions
310 * thrown will have \c type information in the error message.
311 * \param from The region of memory that represents the C++ value to convert to JSON. The pointer comes as the
312 * result of a <tt>static_cast&lt;void*&gt;</tt>, so performing a \c static_cast back to your type is
313 * okay.
314 **/
316 const void* from
317 ) const = 0;
318};
319
320/** An \c adapter is both an \c extractor and a \c serializer. It is made with the idea that for \e most types, you want
321 * to both encode and decode JSON.
322**/
324 public extractor,
325 public serializer
326{
327public:
328 virtual ~adapter() noexcept;
329};
330
331/// Simply put, this class is a collection of \c extractor and \c serializer instances.
332///
333/// Ultimately, \c formats form a directed graph of possible types to load. This allows you to compose formats including
334/// your application with any number of 3rd party libraries an base formats. Imagine an application that has both a user
335/// facing API and an object storage system, both of which speak JSON. When loading from the database, you would like
336/// strict type enforcement -- check that when you say <tt>extract&lt;int&gt;(val)</tt>, that \c val actually has
337/// \c kind::integer. When getting values from the API, you happily convert \c kind::string with the value \c "51" into
338/// the integer \c 51. You really don't want to have to write two versions of decoders for all of your objects: one
339/// which uses the standard checked \c value::as_integer and one that uses \c coerce_integer -- you want the same object
340/// model.
341///
342/// \dot
343/// digraph formats {
344/// defaults [label="formats::defaults"]
345/// coerce [label="formats::coerce"]
346/// lib [label="some_3rd_party"]
347/// my_app [label="my_app_formats"]
348/// db [label="my_app_database_loader"]
349/// api [label="my_app_api_loader"]
350///
351/// my_app -> lib
352/// db -> defaults
353/// db -> my_app
354/// api -> coerce
355/// api -> my_app
356/// }
357/// \enddot
358///
359/// To do this, you would create your object model (called \c my_app_formats in the chart) with the object models for
360/// your application-specific types. This can use any number of 3rd party libraries to get the job done. To make a
361/// functional \c formats, you would \c compose different \c formats instances into a single one. From there,
362///
363/// \code
364/// jsonv::formats get_api_formats()
365/// {
366/// static jsonv::formats instance = jsonv::formats::compose({ jsonv::formats::coerce(), get_app_formats() });
367/// return instance;
368/// }
369///
370/// jsonv::formats get_db_formats()
371/// {
372/// static jsonv::formats instance = jsonv::formats::compose({ jsonv::formats::defaults(), get_app_formats() });
373/// return instance;
374/// }
375///
376/// MyType extract_thing(const jsonv::value& from, bool from_db)
377/// {
378/// return jsonv::extract<MyType>(from, from_db ? get_db_formats() : get_api_formats());
379/// }
380/// \endcode
382{
383public:
384 using list = std::vector<formats>;
385
386public:
387 /** Get the default \c formats instance. This uses \e strict type-checking and behaves by the same rules as the
388 * \c value \c as_ member functions (\c as_integer, \c as_string, etc).
389 *
390 * \note
391 * This function actually returns a \e copy of the default \c formats, so modifications do not affect the actual
392 * instance.
393 **/
395
396 /** Get the global \c formats instance. By default, this is the same as \c defaults, but you can override it with
397 * \c set_global. The \c extract function uses this \c formats instance if none is provided, so this is convenient
398 * if your application only has one type of \c formats to use.
399 *
400 * \note
401 * This function actually returns a \e copy of the global \c formats, so modifications do not affect the actual
402 * instance. If you wish to alter the global formats, use \c set_global.
403 **/
404 static formats global();
405
406 /** Set the \c global \c formats instance.
407 *
408 * \returns the previous value of the global formats instance.
409 **/
411
412 /** Reset the \c global \c formats instance to \c defaults.
413 *
414 * \returns the previous value of the global formats instance.
415 **/
417
418 /** Get the coercing \c formats instance. This uses \e loose type-checking and behaves by the same rules as the
419 * \c coerce_ functions in \c coerce.hpp.
420 *
421 * \note
422 * This function actually returns a \e copy of the default \c formats, so modifications do not affect the actual
423 * instance.
424 **/
425 static formats coerce();
426
427 /** Create a new, empty \c formats instance. By default, this does not know how to extract anything -- not even the
428 * basic types like \c int64_t or \c std::string.
429 **/
431
433
434 /** Create a new (empty) \c formats using the \a bases as backing \c formats. This forms a directed graph of
435 * \c formats objects. When searching for an \c extractor or \c serializer, the \c formats is searched, then each
436 * base is searched depth-first left-to-right.
437 *
438 * \param bases Is the list of \c formats objects to use as bases for the newly-created \c formats. Order matters
439 * -- the \a bases are searched left-to-right, so \c formats that are farther left take precedence
440 * over those more to the right.
441 *
442 * \note
443 * It is impossible to form an endless loop of \c formats objects, since the base of all \c formats are eventually
444 * empty. If there is an existing set of nodes \f$ k \f$ and each new \c format created with \c compose is in
445 * \f$ k+1 \f$, there is no way to create a link from \f$ k \f$ into \f$ k+1 \f$ and so there is no way to create a
446 * circuit.
447 **/
448 static formats compose(const list& bases);
449
450 /** Extract the provided \a type \a from a \c value \a into an area of memory. The \a context is passed to the
451 * \c extractor which performs the conversion. In general, this should not be used directly as it is quite painful
452 * to do so -- prefer \c extraction_context::extract or the free function \c jsonv::extract.
453 *
454 * \throws no_extractor if an \c extractor for \a type could not be found.
455 **/
456 void extract(const std::type_info& type,
458 void* into,
460 ) const;
461
462 /** Get the \c extractor for the given \a type.
463 *
464 * \throws no_extractor if an \c extractor for \a type could not be found.
465 **/
466 const extractor& get_extractor(std::type_index type) const;
467
468 /** Get the \c extractor for the given \a type.
469 *
470 * \throws no_extractor if an \c extractor for \a type could not be found.
471 **/
472 const extractor& get_extractor(const std::type_info& type) const;
473
474 /** Encode the provided value \a from into a JSON \c value. The \a context is passed to the \c serializer which
475 * performs the conversion. In general, this should not be used directly as it is painful to do so -- prefer
476 * \c serialization_context::to_json or the free function \c jsonv::to_json.
477 *
478 * \throws no_serializer if a \c serializer for \a type could not be found.
479 **/
480 value to_json(const std::type_info& type,
481 const void* from,
483 ) const;
484
485 /** Gets the \c serializer for the given \a type.
486 *
487 * \throws no_serializer if a \c serializer for \a type could not be found.
488 **/
489 const serializer& get_serializer(std::type_index type) const;
490
491 /** Gets the \c serializer for the given \a type.
492 *
493 * \throws no_serializer if a \c serializer for \a type could not be found.
494 **/
495 const serializer& get_serializer(const std::type_info& type) const;
496
497 /** Register an \c extractor that lives in some unmanaged space.
498 *
499 * \throws duplicate_type_error if this \c formats instance already has an \c extractor that serves the provided
500 * \c extractor::get_type and the \c duplicate_type_action is \c exception.
501 **/
502 void register_extractor(const extractor*, duplicate_type_action action = duplicate_type_action::exception);
503
504 /** Register an \c extractor with shared ownership between this \c formats instance and anything else.
505 *
506 * \throws duplicate_type_error if this \c formats instance already has an \c extractor that serves the provided
507 * \c extractor::get_type and the \c duplicate_type_action is \c exception.
508 **/
509 void register_extractor(std::shared_ptr<const extractor>,
511
512 /** Register a \c serializer that lives in some managed space.
513 *
514 * \throws duplicate_type_error if this \c formats instance already has a \c serializer that serves the provided
515 * \c serializer::get_type and the \c duplicate_type_action is \c exception.
516 **/
517 void register_serializer(const serializer*, duplicate_type_action action = duplicate_type_action::exception);
518
519 /** Register a \c serializer with shared ownership between this \c formats instance and anything else.
520 *
521 * \throws duplicate_type_error if this \c formats instance already has a \c serializer that serves the provided
522 * \c serializer::get_type and the \c duplicate_type_action is \c exception.
523 **/
524 void register_serializer(std::shared_ptr<const serializer>,
526
527 /** Register an \c adapter that lives in some unmanaged space.
528 *
529 * \throws duplicate_type_error if this \c formats instance already has either an \c extractor or \c serializer
530 * that serves the provided \c adapter::get_type and the \c duplicate_type_action is
531 * \c exception.
532 **/
533 void register_adapter(const adapter*, duplicate_type_action action = duplicate_type_action::exception);
534
535 /** Register an \c adapter with shared ownership between this \c formats instance and anything else.
536 *
537 * \throws duplicate_type_error if this \c formats instance already has either an \c extractor or \c serializer
538 * that serves the provided \c adapter::get_type the \c duplicate_type_action is
539 * \c exception.
540 **/
541 void register_adapter(std::shared_ptr<const adapter>,
543
544 /** Test for equality between this instance and \a other. If two \c formats are equal, they are the \e exact same
545 * node in the graph. Even if one \c formats has the exact same types for the exact same <tt>extractor</tt>s.
546 **/
548
549 /** Test for inequality between this instance and \a other. The opposite of \c operator==. **/
551
552private:
553 struct data;
554
555private:
556 explicit formats(std::vector<std::shared_ptr<const data>> bases);
557
558private:
559 std::shared_ptr<data> _data;
560};
561
562/** Provides extra information to routines used for extraction. **/
564{
565public:
566 /** Create a new instance using the default \c formats (\c formats::global). **/
568
569 /** Create a new instance using the given \a fmt, \a ver and \a p. **/
572 const void* userdata = nullptr
573 );
574
575 virtual ~context_base() noexcept = 0;
576
577 /** Get the \c formats object backing extraction and encoding. **/
578 const jsonv::formats& formats() const
579 {
580 return _formats;
581 }
582
583 /** Get the version this \c extraction_context was created with. **/
585 {
586 return _version;
587 }
588
589 /** Get a pointer to arbitrary user data. **/
590 const void* user_data() const
591 {
592 return _user_data;
593 }
594
595private:
596 jsonv::formats _formats;
597 jsonv::version _version;
598 const void* _user_data;
599};
600
602 public context_base
603{
604public:
605 /// Create a new instance using the default \c formats (\c formats::global).
607
608 /// Create a new instance using the given \a fmt, \a ver and \a p.
612 const void* userdata = nullptr
613 );
614
616
617 /// Get the current \c path this \c extraction_context is extracting for. This is useful when debugging and
618 /// generating error messages.
619 const jsonv::path& path() const
620 {
621 return _path;
622 }
623
624 /** Attempt to extract a \c T from \a from using the \c formats associated with this context.
625 *
626 * \tparam T is the type to extract from \a from. It must be movable.
627 *
628 * \throws extraction_error if anything goes wrong when attempting to extract a value.
629 **/
630 template <typename T>
631 T extract(const value& from) const
632 {
633 alignas(T) unsigned char place[sizeof(T)];
634 extract(typeid(T), from, static_cast<void*>(place));
635 T* ptr = std::launder(reinterpret_cast<T*>(place));
636 auto destroy = detail::on_scope_exit([ptr] { std::destroy_at(ptr); });
637 return std::move(*ptr);
638 }
639
640 void extract(const std::type_info& type,
641 const value& from,
642 void* into
643 ) const;
644
645 /** Attempt to extract a \c T from <tt>from.at_path(subpath)</tt> using the \c formats associated with this context.
646 *
647 * \tparam T is the type to extract from \a from. It must be movable.
648 *
649 * \throws extraction_error if anything goes wrong when attempting to extract a value.
650 **/
651 template <typename T>
653 {
654 alignas(T) unsigned char place[sizeof(T)];
655 extract_sub(typeid(T), from, std::move(subpath), static_cast<void*>(place));
656 T* ptr = std::launder(reinterpret_cast<T*>(place));
657 auto destroy = detail::on_scope_exit([ptr] { std::destroy_at(ptr); });
658 return std::move(*ptr);
659 }
660
661 void extract_sub(const std::type_info& type, const value& from, jsonv::path subpath, void* into) const;
662
663 /** Attempt to extract a \c T from <tt>from.at_path({elem})</tt> using the \c formats associated with this context.
664 *
665 * \tparam T is the type to extract from \a from. It must be movable.
666 *
667 * \throws extraction_error if anything goes wrong when attempting to extract a value.
668 **/
669 template <typename T>
671 {
672 return extract_sub<T>(from, jsonv::path({ elem }));
673 }
674
675private:
676 jsonv::path _path;
677};
678
679/// Extract a C++ value from \a from using the provided \a fmts.
680template <typename T>
681T extract(const value& from, const formats& fmts)
682{
684 return context.extract<T>(from);
685}
686
687/// Extract a C++ value from \a from using \c jsonv::formats::global().
688template <typename T>
690{
692 return context.extract<T>(from);
693}
694
696 public context_base
697{
698public:
699 /// Create a new instance using the default \c formats (\c formats::global).
701
702 /// Create a new instance using the given \a fmt and \a ver.
705 const void* userdata = nullptr
706 );
707
709
710 /// Convenience function for converting a C++ object into a JSON value.
711 ///
712 /// \see formats::to_json
714 value to_json(const T& from) const
715 {
716 return to_json(typeid(T), static_cast<const void*>(&from));
717 }
718
719 /// Dynamically convert a type into a JSON value.
720 ///
721 /// \see formats::to_json
722 value to_json(const std::type_info& type, const void* from) const;
723};
724
725/** Encode a JSON \c value from \a from using the provided \a fmts. **/
726template <typename T>
727value to_json(const T& from, const formats& fmts)
728{
730 return context.to_json(from);
731}
732
733/** Encode a JSON \c value from \a from using \c jsonv::formats::global(). **/
734template <typename T>
736{
738 return context.to_json(from);
739}
740
741/// \}
742
743}
virtual void extract(const extraction_context &context, const value &from, void *into) const override
Extract a the type from a value into a region of memory.
An adapter is both an extractor and a serializer.
Provides extra information to routines used for extraction.
context_base()
Create a new instance using the default formats (formats::global).
const jsonv::version version() const
Get the version this extraction_context was created with.
context_base(jsonv::formats fmt, const jsonv::version &ver=jsonv::version(1), const void *userdata=nullptr)
Create a new instance using the given fmt, ver and p.
const void * user_data() const
Get a pointer to arbitrary user data.
Exception thrown if an insertion of an extractor or serializer into a formats is attempted,...
An adapter for enumeration types.
Configuration for various extraction options. This becomes part of the extraction_context.
extract_options() noexcept
Create an instance with the default options.
duplicate_key_action
When an object key has the same value as a previously-seen key, what should happen?
size_type max_failures() const
on_error
When an error is encountered during extraction, what should happen?
duplicate_key_action on_duplicate_key() const
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.
extraction_context()
Create a new instance using the default formats (formats::global).
T extract(const value &from) const
Attempt to extract a T from from using the formats associated with this context.
T extract_sub(const value &from, path_element elem) const
Attempt to extract a T from from.at_path({elem}) using the formats associated with this context.
extraction_context(jsonv::formats fmt, const jsonv::version &ver=jsonv::version(), jsonv::path p=jsonv::path(), const void *userdata=nullptr)
Create a new instance using the given fmt, ver and p.
Description of a single problem with extraction.
const std::string & message() const noexcept
Human-readable details about the encountered problem.
const std::exception_ptr & nested_ptr() const noexcept
If there was an exception that caused this problem, extra details can be found in the nested exceptio...
problem(jsonv::path path, std::exception_ptr cause) noexcept
Create a problem with a message extracted from cause.
problem(jsonv::path path, std::string message, std::exception_ptr cause) noexcept
const jsonv::path & path() const noexcept
The path this problem was encountered at.
Exception thrown if there is any problem running extract.
extraction_error(jsonv::path path, std::string message, std::exception_ptr cause) noexcept
extraction_error(problem_list problems) noexcept
Create an extraction_error from the given list of problems.
An extractor holds the method for converting JSON source into an arbitrary C++ type.
virtual void extract(const extraction_context &context, const value &from, void *into) const =0
Extract a the type from a value into a region of memory.
virtual const std::type_info & get_type() const =0
Get the run-time type this extractor knows how to extract.
Simply put, this class is a collection of extractor and serializer instances.
static formats global()
Get the global formats instance.
static formats set_global(formats)
Set the global formats instance.
static formats reset_global()
Reset the global formats instance to defaults.
static formats defaults()
Get the default formats instance.
static formats coerce()
Get the coercing formats instance.
formats()
Create a new, empty formats instance.
Thrown when formats::extract does not have an extractor for the provided type.
no_extractor(const std::type_info &type)
Thrown when formats::to_json does not have a serializer for the provided type.
no_serializer(const std::type_info &type)
Create a new exception.
Represents an exact path in some JSON structure.
Definition path.hpp:83
value to_json(const std::type_info &type, const void *from) const
Dynamically convert a type into a JSON value.
serialization_context()
Create a new instance using the default formats (formats::global).
serialization_context(jsonv::formats fmt, const jsonv::version &ver=jsonv::version(), const void *userdata=nullptr)
Create a new instance using the given fmt and ver.
A serializer holds the method for converting an arbitrary C++ type into a value.
virtual value to_json(const serialization_context &context, const void *from) const =0
Create a value from the value in the given region of memory.
virtual const std::type_info & get_type() const =0
Get the run-time type this serialize knows how to encode.
Represents a single JSON value, which can be any one of a potential kind, each behaving slightly diff...
Definition value.hpp:107
Copyright (c) 2014-2020 by Travis Gockel.
#define JSONV_PUBLIC
This function or class is part of the public API for JSON Voorhees.
Definition config.hpp:102
duplicate_type_action
The action to take when an insertion of an extractor or serializer into a formats is attempted,...
T extract(const value &from, const formats &fmts)
Extract a C++ value from from using the provided fmts.
value to_json(const T &from, const formats &fmts)
Encode a JSON value from from using the provided fmts.
@ exception
A duplicate_type_error should be thrown.
@ ignore
The existing extractor or serializer should be kept, but no exception should be thrown.
@ replace
The new extractor or serializer should be inserted, and no exception should be thrown.
STL namespace.
Support for JSONPath.
Definition of the on_scope_exit utility.
std::string_view string_view
A non-owning reference to a string.
Represents a version used to extract and encode JSON objects from C++ classes.
Definition version.hpp:24
Copyright (c) 2012-2020 by Travis Gockel.