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