DAW JSON Link
daw_json_parse_common.h
Go to the documentation of this file.
1 // Copyright (c) Darrell Wright
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //
6 // Official repository: https://github.com/beached/daw_json_link
7 //
8 
9 #pragma once
10 
11 #include "version.h"
12 
13 #include "daw_json_assert.h"
14 #include "daw_json_enums.h"
15 #include "daw_json_exec_modes.h"
17 #include "daw_json_name.h"
18 #include "daw_json_option_bits.h"
19 #include "daw_json_traits.h"
20 #include "daw_json_type_options.h"
21 #include "daw_json_value_fwd.h"
22 
23 #include <daw/cpp_17.h>
24 #include <daw/daw_allocator_construct.h>
25 #include <daw/daw_arith_traits.h>
26 #include <daw/daw_cpp_feature_check.h>
27 #include <daw/daw_fwd_pack_apply.h>
28 #include <daw/daw_move.h>
29 #include <daw/daw_scope_guard.h>
30 #include <daw/daw_string_view.h>
31 #include <daw/daw_traits.h>
33 
34 #include <array>
35 #include <cstddef>
36 #include <iterator>
37 #include <optional>
38 #include <string>
39 #include <string_view>
40 #include <vector>
41 
42 namespace daw::json {
43  inline namespace DAW_JSON_VER {
44  namespace json_details {
45  DAW_MAKE_REQ_TRAIT_TYPE( is_json_member_list_v,
46  T::i_am_a_json_member_list );
47 
48  template<typename T>
49  using ordered_member_subtype_test = typename T::json_member;
50 
51  template<typename T>
52  using ordered_member_subtype_t =
53  typename daw::detected_or_t<T, ordered_member_subtype_test, T>;
54 
55  template<typename T, typename Default>
56  inline constexpr auto json_class_constructor =
57  json_class_constructor_t<T, Default>{ };
58 
59  template<typename Value, typename Constructor, typename ParseState,
60  typename... Args>
61  DAW_ATTRIB_INLINE static constexpr auto
62  construct_value( ParseState &parse_state, Args &&...args ) {
63  // Silence MSVC warning, used in other if constexpr case
64  (void)parse_state;
65  if constexpr( ParseState::has_allocator ) {
66  auto alloc = parse_state.template get_allocator_for<Value>( );
67  return daw::try_alloc_construct<Value, Constructor>(
68  std::move( alloc ), DAW_FWD( args )... );
69  } else {
70  static_assert(
71  std::is_invocable_v<Constructor, Args...>,
72  "Unable to construct value with the supplied arguments" );
73  return Constructor{ }( DAW_FWD2( Args, args )... );
74  }
75  }
76 
77 #if not defined( DAW_JSON_USE_GENERIC_LAMBDAS )
78  template<typename Constructor>
79  struct construct_value_tp_invoke_t {
80  template<typename... TArgs, std::size_t... Is>
81  DAW_ATTRIB_INLINE constexpr auto
82  operator( )( fwd_pack<TArgs...> &&tp,
83  std::index_sequence<Is...> ) const {
84  return Constructor{ }( get<Is>( std::move( tp ) )... );
85  }
86 
87  template<typename... TArgs, typename Allocator, std::size_t... Is>
88  DAW_ATTRIB_INLINE constexpr auto
89  operator( )( fwd_pack<TArgs...> &&tp, Allocator &alloc,
90  std::index_sequence<Is...> ) const {
91  return Constructor{ }( get<Is>( std::move( tp ) )...,
92  DAW_FWD( alloc ) );
93  }
94 
95  template<typename Alloc, typename... TArgs, std::size_t... Is>
96  DAW_ATTRIB_INLINE constexpr auto
97  operator( )( std::allocator_arg_t, Alloc &&alloc,
98  fwd_pack<TArgs...> &&tp,
99  std::index_sequence<Is...> ) const {
100 
101  return Constructor{ }( std::allocator_arg, DAW_FWD( alloc ),
102  get<Is>( std::move( tp ) )... );
103  }
104  };
105  template<typename Constructor>
106  inline constexpr auto construct_value_tp_invoke =
107  construct_value_tp_invoke_t<Constructor>{ };
108 #endif
109 
110  template<typename Value, typename Constructor, typename ParseState,
111  typename... Args>
112  DAW_ATTRIB_FLATINLINE static inline constexpr auto
113  construct_value_tp( ParseState &parse_state,
114  fwd_pack<Args...> &&tp_args ) {
115 
116 #if defined( DAW_JSON_USE_GENERIC_LAMBDAS )
117  if constexpr( ParseState::has_allocator ) {
118  using alloc_t =
119  typename ParseState::template allocator_type_as<Value>;
120  auto alloc = parse_state.template get_allocator_for<Value>( );
121  if constexpr( std::is_invocable_v<Constructor, Args..., alloc_t> ) {
122  return [&]<std::size_t... Is>( std::index_sequence<Is...> ) {
123  return Constructor{ }( get<Is>( std::move( tp_args ) )...,
124  std::move( alloc ) );
125  }( std::make_index_sequence<sizeof...( Args )>{ } );
126  } else if constexpr( std::is_invocable_v<Constructor,
127  std::allocator_arg_t,
128  alloc_t, Args...> ) {
129  return [&]<std::size_t... Is>( std::index_sequence<Is...> ) {
130  return Constructor{ }( std::allocator_arg, std::move( alloc ),
131  get<Is>( std::move( tp_args ) )... );
132  }( std::make_index_sequence<sizeof...( Args )>{ } );
133  } else {
134  static_assert(
135  std::is_invocable_v<Constructor, Args...>,
136  "Unable to construct value with the supplied arguments" );
137  return [&]<std::size_t... Is>( std::index_sequence<Is...> ) {
138  return Constructor{ }( get<Is>( std::move( tp_args ) )... );
139  }( std::make_index_sequence<sizeof...( Args )>{ } );
140  }
141  } else {
142  // Silence MSVC warning, used in other if constexpr case
143  (void)parse_state;
144  static_assert(
145  std::is_invocable_v<Constructor, Args...>,
146  "Unable to construct value with the supplied arguments" );
147  return [&]<std::size_t... Is>( std::index_sequence<Is...> ) {
148  return Constructor{ }( get<Is>( std::move( tp_args ) )... );
149  }( std::make_index_sequence<sizeof...( Args )>{ } );
150  }
151 #else
152  if constexpr( ParseState::has_allocator ) {
153  using alloc_t =
154  typename ParseState::template allocator_type_as<Value>;
155  auto alloc = parse_state.template get_allocator_for<Value>( );
156  if constexpr( std::is_invocable_v<Constructor, Args..., alloc_t> ) {
157  return construct_value_tp_invoke<Constructor>(
158  std::move( tp_args ), std::move( alloc ),
159  std::index_sequence_for<Args...>{ } );
160  } else if constexpr( std::is_invocable_v<Constructor,
161  std::allocator_arg_t,
162  alloc_t, Args...> ) {
163  return construct_value_tp_invoke<Constructor>(
164  std::allocator_arg, std::move( alloc ), std::move( tp_args ),
165  std::index_sequence_for<Args...>{ } );
166  } else {
167  static_assert(
168  std::is_invocable_v<Constructor, Args...>,
169  "Unable to construct value with the supplied arguments" );
170  return construct_value_tp_invoke<Constructor>(
171  std::move( tp_args ), std::index_sequence_for<Args...>{ } );
172  }
173  } else {
174  // Silence MSVC warning, used in other if constexpr case
175  (void)parse_state;
176  static_assert(
177  std::is_invocable_v<Constructor, Args...>,
178  "Unable to construct value with the supplied arguments" );
179  return construct_value_tp_invoke<Constructor>(
180  std::move( tp_args ), std::index_sequence_for<Args...>{ } );
181  }
182 #endif
183  }
184 
185  template<typename T>
186  inline constexpr bool has_json_data_contract_trait_v =
187  not std::is_same_v<missing_json_data_contract_for_or_unknown_type<T>,
189 
190  template<typename T>
191  using has_json_data_contract_trait =
192  std::bool_constant<has_json_data_contract_trait_v<T>>;
193 
195  has_json_to_json_data_v,
196  json_data_contract<T>::to_json_data( std::declval<T &>( ) ) );
197 
199  is_submember_tagged_variant_v,
201 
202  template<typename T>
203  using json_nullable_member_type_t = typename T::member_type;
204 
205  /***
206  * Helpers to set options on json_ types
207  */
208 
209  template<json_options_t CurrentOptions, auto option, auto... options>
210  inline constexpr json_options_t number_opts_set =
211  set_bits( number_opts, CurrentOptions, option, options... );
212 
213  template<json_options_t CurrentOptions, auto option, auto... options>
214  inline constexpr json_options_t bool_opts_set =
215  set_bits( bool_opts, CurrentOptions, option, options... );
216 
217  template<json_options_t CurrentOptions, auto option, auto... options>
218  inline constexpr json_options_t string_opts_set =
219  set_bits( string_opts, CurrentOptions, option, options... );
220 
221  template<json_options_t CurrentOptions, auto option, auto... options>
222  inline constexpr json_options_t string_raw_opts_set =
223  set_bits( string_raw_opts, CurrentOptions, option, options... );
224 
225  template<json_options_t CurrentOptions, auto option, auto... options>
226  inline constexpr json_options_t json_custom_opts_set =
227  set_bits( json_custom_opts, CurrentOptions, option, options... );
228 
229  /*
230  template<json_options_t CurrentOptions, auto option, auto... options>
231  inline constexpr json_options_t tuple_opts_set =
232  set_bits( tuple_opts, CurrentOptions, option, options... );
233  */
234  } // namespace json_details
235 
236  namespace json_base {
243  template<typename T, typename JsonMember = use_default,
244  JsonNullable NullableType = JsonNullable::Nullable,
245  typename Constructor = use_default>
247 
248  } // namespace json_base
249  namespace json_details {
250  template<typename T>
251  inline constexpr bool is_json_nullable_v = false;
252 
253  template<typename T, typename JsonMember, JsonNullable NullableType,
254  typename Constructor>
255  inline constexpr bool is_json_nullable_v<
257  true;
258 
259  template<typename T>
260  struct json_empty_class {
261  static_assert( std::is_empty_v<T>, "T is expected to empty" );
262  using i_am_a_json_type = void;
263  using i_am_a_deduced_empty_class = void;
264  using wrapped_type = T;
265 
266  using constructor_t = default_constructor<T>;
267  using parse_to_t = T;
268 
269  static constexpr JsonParseTypes expected_type = JsonParseTypes::Class;
270 
271  static constexpr JsonBaseParseTypes underlying_json_type =
272  JsonBaseParseTypes::Class;
273  };
274 
275  template<typename T>
276  inline constexpr bool is_deduced_empty_class_v<
277  T, std::void_t<typename T::i_am_a_deduced_empty_class>> = true;
278 
279  template<typename T>
280  struct json_ordered_class {
281  static_assert( can_convert_to_tuple_v<T>, "T is expected to empty" );
282  using i_am_a_json_type = void;
283  using i_am_a_deduced_ordered_class = void;
284  using wrapped_type = T;
285 
286  using constructor_t = default_constructor<T>;
287  using parse_to_t = T;
288 
289  static constexpr JsonParseTypes expected_type = JsonParseTypes::Tuple;
290 
291  static constexpr JsonBaseParseTypes underlying_json_type =
292  JsonBaseParseTypes::Class;
293  };
294  } // namespace json_details
295 
296  namespace json_base {
297 
298  template<typename T, typename Constructor = use_default>
299  struct json_class;
300 
301  template<typename T, JsonNullable NullableType = JsonNullable::Nullable,
302  typename Constructor = use_default>
305  Constructor>;
306 
307  template<typename JsonElement, typename Container = use_default,
308  typename Constructor = use_default>
309  struct json_array;
310 
311  template<typename T, typename FromJsonConverter = use_default,
312  typename ToJsonConverter = use_default,
314  struct json_custom;
315 
316  template<typename Variant, typename JsonElements = use_default,
317  typename Constructor = use_default>
318  struct json_variant;
319 
320  template<typename T, typename TagMember, typename Switcher,
321  typename JsonElements = use_default,
322  typename Constructor = use_default>
324 
325  template<typename T, json_options_t Options = string_raw_opts_def,
326  typename Constructor = use_default>
328 
329  template<typename T, json_options_t Options = string_raw_opts_def,
330  JsonNullable NullableType = JsonNullable::Nullable,
331  typename Constructor = use_default>
334  NullableType, Constructor>;
335 
336  template<typename T, json_options_t Options = string_opts_def,
337  typename Constructor = use_default>
338  struct json_string;
339 
340  template<typename T, json_options_t Options = string_opts_def,
341  JsonNullable NullableType = JsonNullable::Nullable,
342  typename Constructor = use_default>
345  NullableType, Constructor>;
346 
347  template<typename T, json_options_t Options = bool_opts_def,
348  typename Constructor = use_default>
349  struct json_bool;
350 
351  template<typename T, json_options_t Options = bool_opts_def,
352  JsonNullable NullableType = JsonNullable::Nullable,
353  typename Constructor = use_default>
356  NullableType, Constructor>;
357 
358  template<typename T, typename Constructor = use_default>
359  struct json_date;
360 
361  template<typename T, json_options_t Options = number_opts_def,
362  typename Constructor = use_default>
363  struct json_number;
364 
365  template<typename T, json_options_t Options = number_opts_def,
366  JsonNullable NullableType = JsonNullable::Nullable,
367  typename Constructor = use_default>
370  NullableType, Constructor>;
371 
372  template<typename Container, typename JsonValueType = use_default,
373  typename JsonKeyType = use_default,
374  typename Constructor = use_default>
376 
377  template<typename Container, typename JsonValueType = use_default,
378  typename JsonKeyType = use_default,
379  typename Constructor = use_default>
381 
382  template<typename Container, typename JsonValueType, typename JsonKeyType,
383  JsonNullable NullableType = JsonNullable::Nullable,
384  typename Constructor = use_default>
386  json_nullable<Container,
388  JsonValueType, JsonKeyType>,
389  NullableType, Constructor>;
390 
391  template<typename Tuple, typename JsonTupleTypesList = use_default,
392  typename Constructor = use_default>
393  struct json_tuple;
394 
395  template<typename Tuple, typename JsonTupleTypesList = use_default,
396  JsonNullable NullableType = JsonNullable::Nullable,
397  typename Constructor = use_default>
399  Tuple, json_tuple<json_details::unwrapped_t<Tuple>, JsonTupleTypesList>,
400  NullableType, Constructor>;
401 
402  /***
403  * json_raw allows for raw JSON access to the member data. It requires a
404  * type that is constructable from (char const *, std::size_t) arguments
405  * and for serialization requires that it can be passed to
406  * std::begin/std::end and the iterator returned has a value_type of char
407  * @tparam T type to hold raw JSON data, defaults to json_value
408  * @tparam Constructor A callable used to construct T.
409  * @tparam Nullable Does the value have to exist in the document or can it
410  * have a null value
411  */
412  template<typename T, typename Constructor = use_default>
413  struct json_raw;
414 
415  /***
416  * json_raw_null allows for raw JSON access to the nullable member data.
417  * It requires a type that is constructable from (char const *,
418  * std::size_t) arguments and for serialization requires that it can be
419  * passed to std::begin/std::end and the iterator returned has a
420  * value_type of char
421  * @tparam T type to hold raw JSON data, defaults to json_value
422  * @tparam Constructor A callable used to construct T.
423  */
424  template<typename T, JsonNullable NullableType = JsonNullable::Nullable,
425  typename Constructor = use_default>
428  Constructor>;
429  } // namespace json_base
430 
431  namespace json_details {
432  template<typename T>
433  DAW_ATTRIB_INLINE DAW_CONSTEVAL JsonParseTypes
434  number_parse_type_impl_test( ) {
435  if constexpr( daw::is_floating_point_v<T> ) {
436  return JsonParseTypes::Real;
437  } else if constexpr( daw::is_signed_v<T> ) {
438  return JsonParseTypes::Signed;
439  } else {
440  static_assert( daw::is_unsigned_v<T> );
441  return JsonParseTypes::Unsigned;
442  }
443  }
444 
445  template<typename T>
446  DAW_ATTRIB_INLINE DAW_CONSTEVAL JsonParseTypes number_parse_type_test( ) {
447  if constexpr( std::is_enum_v<T> ) {
448  return number_parse_type_impl_test<std::underlying_type_t<T>>( );
449  } else {
450  return number_parse_type_impl_test<T>( );
451  }
452  }
453 
454  template<typename T>
455  inline constexpr JsonParseTypes number_parse_type_v =
456  number_parse_type_test<T>( );
457 
458  template<typename, typename = void>
459  struct json_deduced_type_map {
460  static constexpr bool is_null = false;
461  static constexpr JsonParseTypes parse_type = JsonParseTypes::Unknown;
462 
463  static constexpr bool type_map_found = false;
464  };
465 
466  template<typename JsonType>
467  DAW_JSON_REQUIRES( is_a_json_type_v<JsonType> )
468  struct json_deduced_type_map<
469  JsonType DAW_JSON_ENABLEIF_S( is_a_json_type_v<JsonType> )> {
470  static constexpr bool is_null = false;
471  static constexpr JsonParseTypes parse_type = JsonParseTypes::Unknown;
472 
473  using type = JsonType;
474  static constexpr bool type_map_found = true;
475  };
476 
477  template<typename T>
478  DAW_JSON_REQUIRES( has_json_data_contract_trait_v<T> )
479  struct json_deduced_type_map<
480  T DAW_JSON_ENABLEIF_S( has_json_data_contract_trait_v<T> )> {
481  static constexpr bool is_null = false;
482  using type = typename json_data_contract<T>::type;
483  static_assert( is_json_member_list_v<type>,
484  "Expected a JSON member list" );
485  static constexpr JsonParseTypes parse_type = JsonParseTypes::Unknown;
486 
487  static constexpr bool type_map_found = true;
488  };
489 
490  template<>
491  struct json_deduced_type_map<daw::string_view> {
492  static constexpr bool is_null = false;
493  static constexpr JsonParseTypes parse_type = JsonParseTypes::StringRaw;
494 
495  static constexpr bool type_map_found = true;
496  };
497 
498  template<>
499  struct json_deduced_type_map<std::string_view> {
500  static constexpr bool is_null = false;
501  static constexpr JsonParseTypes parse_type = JsonParseTypes::StringRaw;
502 
503  static constexpr bool type_map_found = true;
504  };
505 
506  template<>
507  struct json_deduced_type_map<std::string> {
508  static constexpr bool is_null = false;
509  static constexpr JsonParseTypes parse_type =
510  JsonParseTypes::StringEscaped;
511 
512  static constexpr bool type_map_found = true;
513  };
514 
515  template<>
516  struct json_deduced_type_map<bool> {
517  static constexpr bool is_null = false;
518  static constexpr JsonParseTypes parse_type = JsonParseTypes::Bool;
519 
520  static constexpr bool type_map_found = true;
521  };
522 
523  // libc++ has a non-conforming vector<bool>::const_reference as it isn't
524  // bool https://bugs.llvm.org/show_bug.cgi?id=16077
525 #if defined( _LIBCPP_VERSION )
526  template<>
527  struct json_deduced_type_map<
528  typename std::vector<bool>::const_reference> {
529 
530  static constexpr bool is_null = false;
531  static constexpr JsonParseTypes parse_type = JsonParseTypes::Bool;
532 
533  static constexpr bool type_map_found = true;
534  };
535 #endif
536 
537  template<typename Integer>
539  not json_details::has_json_data_contract_trait_v<Integer> and
540  daw::is_integral_v<Integer> )
541  struct json_deduced_type_map<Integer DAW_JSON_ENABLEIF_S(
542  not json_details::has_json_data_contract_trait_v<Integer> and
543  daw::is_integral_v<Integer> )> {
544  static constexpr bool is_null = false;
545  static constexpr JsonParseTypes parse_type =
546  daw::is_signed_v<Integer> ? JsonParseTypes::Signed
547  : JsonParseTypes::Unsigned;
548 
549  static constexpr bool type_map_found = true;
550  };
551 
552  template<typename Enum>
554  not json_details::has_json_data_contract_trait_v<Enum> and
555  std::is_enum_v<Enum> )
556  struct json_deduced_type_map<Enum DAW_JSON_ENABLEIF_S(
557  not json_details::has_json_data_contract_trait_v<Enum> and
558  std::is_enum_v<Enum> )> {
559  static constexpr bool is_null = false;
560  static constexpr JsonParseTypes parse_type =
561  daw::is_signed_v<std::underlying_type<Enum>>
562  ? JsonParseTypes::Signed
563  : JsonParseTypes::Unsigned;
564 
565  static constexpr bool type_map_found = true;
566  };
567 
568  template<typename FloatingPoint>
570  not json_details::has_json_data_contract_trait_v<FloatingPoint> and
571  daw::is_floating_point_v<FloatingPoint> )
572  struct json_deduced_type_map<FloatingPoint DAW_JSON_ENABLEIF_S(
573  not json_details::has_json_data_contract_trait_v<FloatingPoint> and
574  daw::is_floating_point_v<FloatingPoint> )> {
575  static constexpr bool is_null = false;
576  static constexpr JsonParseTypes parse_type = JsonParseTypes::Real;
577 
578  static constexpr bool type_map_found = true;
579  };
580 
581  template<typename Tuple>
583  not json_details::has_json_data_contract_trait_v<Tuple> and
584  is_tuple_v<Tuple> )
585  struct json_deduced_type_map<Tuple DAW_JSON_ENABLEIF_S(
586  not json_details::has_json_data_contract_trait_v<Tuple> and
587  is_tuple_v<Tuple> )> {
588  static constexpr bool is_null = false;
589  static constexpr JsonParseTypes parse_type = JsonParseTypes::Tuple;
590 
591  static constexpr bool type_map_found = true;
592  };
593 
594  namespace container_detect {
595  template<typename T>
596  using is_string_test =
597  decltype( (void)( std::begin( std::declval<T &>( ) ) ),
598  (void)( std::end( std::declval<T &>( ) ) ),
599  std::declval<typename T::value_type>( ) );
600  } // namespace container_detect
601 
602  template<typename String>
603  inline constexpr bool is_string_v = std::is_convertible_v<
604  char, daw::detected_t<container_detect::is_string_test, String>>;
605 
607  is_associative_container_v,
608  ( (void)( std::begin( std::declval<T &>( ) ) ),
609  (void)( std::end( std::declval<T &>( ) ) ),
610  (void)( std::declval<typename T::value_type>( ) ),
611  (void)( std::declval<typename T::key_type>( ) ),
612  (void)( std::declval<typename T::mapped_type>( ) ) ) );
613 
614  template<typename T>
615  using is_associative_container =
616  std::bool_constant<is_associative_container_v<T>>;
617 
618  template<typename AssociativeContainer>
620  not has_json_data_contract_trait_v<AssociativeContainer> and
621  is_associative_container_v<AssociativeContainer> )
622  struct json_deduced_type_map<AssociativeContainer DAW_JSON_ENABLEIF_S(
623  not has_json_data_contract_trait_v<AssociativeContainer> and
624  is_associative_container_v<AssociativeContainer> )> {
625  static constexpr bool is_null = false;
626  using key = typename AssociativeContainer::key_type;
627  using value = typename AssociativeContainer::mapped_type;
628  static constexpr JsonParseTypes parse_type = JsonParseTypes::KeyValue;
629 
630  static constexpr bool type_map_found = true;
631  };
632 
633  template<typename T>
634  inline constexpr bool is_deduced_array_v =
635  not has_json_data_contract_trait_v<T> and
636  not is_associative_container_v<T> and concepts::is_container_v<T> and
637  not is_string_v<T>;
638 
639  template<typename Container>
640  DAW_JSON_REQUIRES( is_deduced_array_v<Container> )
641  struct json_deduced_type_map<
642  Container DAW_JSON_ENABLEIF_S( is_deduced_array_v<Container> )> {
643  static constexpr bool is_null = false;
644  using value = typename Container::value_type;
645  static constexpr JsonParseTypes parse_type = JsonParseTypes::Array;
646 
647  static constexpr bool type_map_found = true;
648  };
649 
650  template<typename T>
651  inline constexpr bool has_nullable_type_map_v =
652  concepts::is_nullable_value_v<T> and
653  not has_json_data_contract_trait_v<T> and
654  daw::is_detected_v<json_deduced_type_map,
655  concepts::nullable_value_type_t<T>>;
656 
657  template<typename T>
658  DAW_JSON_REQUIRES( has_nullable_type_map_v<T> )
659  struct json_deduced_type_map<
660  T DAW_JSON_ENABLEIF_S( has_nullable_type_map_v<T> )> {
661  static constexpr bool is_null = true;
662  using sub_type = concepts::nullable_value_type_t<T>;
663  using type = json_deduced_type_map<sub_type>;
664  static constexpr JsonParseTypes parse_type = type::parse_type;
665  static constexpr bool type_map_found = true;
666  };
667 
668  template<typename T>
669  inline constexpr bool has_deduced_type_mapping_v =
670  json_deduced_type_map<T>::type_map_found;
671 
672  template<typename... Ts>
673  inline constexpr bool are_deduced_type_mapped_v =
674  ( has_deduced_type_mapping_v<Ts> and ... );
675 
676  template<typename Mapped, bool Found = true>
677  struct json_link_quick_map_type {
678  static constexpr bool value = Found;
679  using mapped_type = Mapped;
680  };
681 
682  template<JsonParseTypes Value>
683  inline constexpr bool is_arithmetic_parse_type_v =
684  daw::traits::equal_to_any_of_v<Value, JsonParseTypes::Signed,
685  JsonParseTypes::Unsigned,
686  JsonParseTypes::Real>;
687 
688  template<typename T>
689  DAW_ATTRIB_INLINE DAW_CONSTEVAL auto json_link_quick_map( ) noexcept {
690  if constexpr( is_a_json_type_v<T> ) {
691  return json_link_quick_map_type<T>{ };
692  } else if constexpr( has_deduced_type_mapping_v<T> ) {
693  using mapped_type_t = json_deduced_type_map<T>;
694  using parse_type = daw::constant<mapped_type_t::parse_type>;
695  using is_null = daw::constant<mapped_type_t::is_null>;
696  if constexpr( parse_type::value == JsonParseTypes::Unknown ) {
697  if constexpr( is_null::value ) {
698  if constexpr( has_json_data_contract_trait_v<
699  typename mapped_type_t::sub_type> ) {
700  return json_link_quick_map_type<
701  json_base::json_class_null<T>>{ };
702  } else {
703  return json_link_quick_map_type<json_base::json_raw_null<T>>{ };
704  }
705  } else {
706  return json_link_quick_map_type<json_base::json_raw<T>>{ };
707  }
708  } else if constexpr( parse_type::value ==
709  JsonParseTypes::StringRaw ) {
710  if constexpr( is_null::value ) {
711  return json_link_quick_map_type<
712  json_base::json_string_raw_null<T>>{ };
713  } else {
714  return json_link_quick_map_type<json_base::json_string_raw<T>>{ };
715  }
716  } else if constexpr( parse_type::value ==
717  JsonParseTypes::StringEscaped ) {
718  if constexpr( is_null::value ) {
719  return json_link_quick_map_type<
720  json_base::json_string_null<T>>{ };
721  } else {
722  return json_link_quick_map_type<json_base::json_string<T>>{ };
723  }
724  } else if constexpr( parse_type::value == JsonParseTypes::Bool ) {
725  if constexpr( is_null::value ) {
726  return json_link_quick_map_type<json_base::json_bool_null<T>>{ };
727  } else {
728  return json_link_quick_map_type<json_base::json_bool<T>>{ };
729  }
730  } else if constexpr( is_arithmetic_parse_type_v<parse_type::value> ) {
731  if constexpr( is_null::value ) {
732  return json_link_quick_map_type<
733  json_base::json_number_null<T>>{ };
734  } else {
735  return json_link_quick_map_type<json_base::json_number<T>>{ };
736  }
737  } else if constexpr( parse_type::value == JsonParseTypes::Tuple ) {
738  if constexpr( is_null::value ) {
739  return json_link_quick_map_type<json_base::json_tuple_null<T>>{ };
740  } else {
741  return json_link_quick_map_type<json_base::json_tuple<T>>{ };
742  }
743  } else if constexpr( parse_type::value == JsonParseTypes::KeyValue ) {
744  if constexpr( is_null::value ) {
745  using b_t = json_base_type_t<mapped_type_t>;
746  using k_t = typename b_t::key;
747  using v_t = typename b_t::value;
748  return json_link_quick_map_type<
749  json_base::json_key_value_null<T, v_t, k_t>>{ };
750  } else {
751  using k_t = typename mapped_type_t::key;
752  using v_t = typename mapped_type_t::value;
753  return json_link_quick_map_type<
754  json_base::json_key_value<T, v_t, k_t>>{ };
755  }
756  } else if constexpr( parse_type::value == JsonParseTypes::Array ) {
757  if constexpr( is_null::value ) {
758  using b_t = json_base_type_t<mapped_type_t>;
759  using v_t = typename b_t::value;
760  return json_link_quick_map_type<
761  json_base::json_nullable<T, json_base::json_array<v_t, T>>>{ };
762  } else {
763  using v_t = typename mapped_type_t::value;
764  return json_link_quick_map_type<json_base::json_array<v_t, T>>{ };
765  }
766  } else {
767  return json_link_quick_map_type<void, false>{ };
768  }
769  } else {
770  return json_link_quick_map_type<void, false>{ };
771  }
772  }
773 
775  template<typename T>
776  inline constexpr bool has_json_link_quick_map_v =
777  decltype( json_link_quick_map<T>( ) )::value;
778 
780  template<typename T>
781  using json_link_quick_map_t =
782  typename decltype( json_link_quick_map<T>( ) )::mapped_type;
783 
784  template<typename JsonType>
785  struct json_class_map_type {
786  using type = typename json_data_contract_trait_t<JsonType>::json_member;
787  };
788 
789  template<typename>
790  struct is_json_class_map : std::false_type {};
791 
792  template<typename T>
793  inline constexpr bool is_json_class_map_v =
794  has_json_data_contract_trait_v<T> and
795  is_json_class_map_v<json_data_contract_trait_t<T>>;
796 
797  template<typename T>
798  DAW_ATTRIB_INLINE DAW_CONSTEVAL auto json_deduced_type_impl( ) noexcept {
799  if constexpr( is_a_basic_json_value<T> ) {
800  return daw::traits::identity<json_base::json_raw<T>>{ };
801  } else if constexpr( is_an_ordered_member_v<T> ) {
802  using type = T;
803  return daw::traits::identity<type>{ };
804  } else if constexpr( has_json_data_contract_trait_v<T> ) {
805  static_assert( not std::is_same_v<T, void> );
806 
807  using type = json_base::json_class<T>;
808 
809  static_assert( not std::is_same_v<daw::remove_cvref_t<type>, void>,
810  "Detection failure" );
811  static_assert( not is_nonesuch_v<remove_cvref_t<type>>,
812  "Detection failure" );
813  return daw::traits::identity<type>{ };
814  } else if constexpr( has_json_link_quick_map_v<T> ) {
815  static_assert( not std::is_same_v<T, void> );
816  using type = json_link_quick_map_t<T>;
817  using rcvref_type = remove_cvref_t<type>;
818  static_assert( not std::is_same_v<rcvref_type, void>,
819  "Detection failure" );
820  static_assert( not is_nonesuch_v<rcvref_type>, "Detection failure" );
821  return daw::traits::identity<type>{ };
822  } else if constexpr( is_a_json_type_v<T> ) {
823  static_assert( not std::is_same_v<T, void> );
824  using type =
825  typename daw::conditional_t<is_json_class_map_v<T>,
826  json_class_map_type<T>,
827  daw::traits::identity<T>>::type;
828  static_assert( not std::is_same_v<daw::remove_cvref_t<type>, void>,
829  "Detection failure" );
830  static_assert( not is_nonesuch_v<remove_cvref_t<type>>,
831  "Detection failure" );
832  return daw::traits::identity<type>{ };
833  } else if constexpr( concepts::is_nullable_value_v<T> ) {
834  using value_type = concepts::nullable_value_type_t<T>;
835  using sub_type =
836  typename decltype( json_deduced_type_impl<value_type>( ) )::type;
837  using type = json_base::json_nullable<T, sub_type>;
838  return daw::traits::identity<type>{ };
839  } else if constexpr( concepts::is_container_v<T> ) {
840  using type = json_base::json_array<typename T::value_type, T>;
841  return daw::traits::identity<type>{ };
842  } else if constexpr( std::is_empty_v<T> and
843  std::is_default_constructible_v<T> ) {
844  // Allow empty/default constructible types to work without mapping
845  using type = json_details::json_empty_class<T>;
846  return daw::traits::identity<type>{ };
847  } else if constexpr( can_convert_to_tuple_v<T> ) {
848  using type = json_base::json_tuple<T>;
849  return daw::traits::identity<type>{ };
850  } else {
851  static_assert( daw::deduced_false_v<T>,
852  "Could not deduced data contract type" );
853  }
854  }
855 
856  template<typename T>
857  using json_deduced_type =
858  typename DAW_TYPEOF( json_deduced_type_impl<T>( ) )::type;
859 
860  template<typename T>
861  inline constexpr bool has_json_deduced_type_v =
862  not std::is_same_v<json_deduced_type<T>,
863  missing_json_data_contract_for_or_unknown_type<T>>;
864 
865  template<typename... Ts>
866  inline constexpr bool all_have_deduced_type_v =
867  ( has_json_deduced_type_v<Ts> and ... );
868 
869  template<typename JsonElement, typename Container, typename Constructor>
870  struct json_constructor<
871  json_base::json_array<JsonElement, Container, Constructor>> {
872  using json_element_t = json_deduced_type<JsonElement>;
873  using json_element_parse_to_t = json_result_t<json_element_t>;
874 
875  using container_t =
876  daw::conditional_t<std::is_same_v<Container, use_default>,
877  std::vector<json_element_parse_to_t>, Container>;
878 
879  using type =
880  daw::conditional_t<std::is_same_v<use_default, Constructor>,
881  default_constructor<container_t>, Constructor>;
882 
883  static_assert(
884  std::is_invocable_v<type, json_element_parse_to_t const *,
885  json_element_parse_to_t const *>,
886  "Constructor must support copy and/or move construction" );
887  };
888 
889  template<typename JsonElement, typename Container, typename Constructor>
890  struct json_result<
891  json_base::json_array<JsonElement, Container, Constructor>> {
892  using constructor_t = typename json_constructor<
893  json_base::json_array<JsonElement, Container, Constructor>>::type;
894  using json_element_t = json_deduced_type<JsonElement>;
895  using json_element_parse_to_t =
896  typename json_result<json_element_t>::type;
897  using type =
898  std::invoke_result_t<constructor_t, json_element_parse_to_t const *,
899  json_element_parse_to_t const *>;
900  };
901 
902  template<typename T>
903  inline constexpr bool has_unnamed_default_type_mapping_v =
904  has_json_deduced_type_v<T>;
905 
906  template<typename JsonMember>
907  using from_json_result_t = json_result_t<json_deduced_type<JsonMember>>;
908 
909  template<typename Constructor, typename... Members>
910  using json_class_parse_result_impl2 =
911  std::invoke_result_t<Constructor, json_result_t<Members>...>;
912 
913  template<typename Constructor, typename... Members>
914  using json_class_parse_result_impl =
915  daw::detected_t<json_class_parse_result_impl2, Constructor, Members...>;
916 
917  template<typename Constructor, typename... Members>
918  struct could_not_construct_from_members_error;
919 
920  template<typename Constructor, typename... Members>
921  using json_class_parse_result_t = typename daw::conditional_t<
922  std::is_invocable_v<Constructor, json_result_t<Members>...>,
923  std::invoke_result<Constructor, json_result_t<Members>...>,
924  daw::traits::identity<could_not_construct_from_members_error<
925  Constructor, Members...>>>::type;
926 
927  template<typename JsonMember>
928  using dependent_member_t = typename JsonMember::dependent_member;
929 
930  template<typename JsonMember, typename = void>
931  inline constexpr bool has_dependent_member_v = false;
932 
933  template<typename JsonMember>
934  inline constexpr bool has_dependent_member_v<
935  JsonMember, std::void_t<dependent_member_t<JsonMember>>> = true;
936 
937  DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( has_nullable_dependent_member_v,
938  T::member_type::dependent_member );
939 
940  template<typename JsonMember>
941  DAW_JSON_REQUIRES( is_json_nullable_v<JsonMember> )
942  inline constexpr bool has_dependent_member_v<
943  JsonMember DAW_JSON_ENABLEIF_S( is_json_nullable_v<JsonMember> )> =
944  has_nullable_dependent_member_v<JsonMember>;
945 
946  template<typename Constructor>
947  [[nodiscard]] DAW_ATTRIB_INLINE constexpr auto
948  construct_nullable_empty( ) {
949  if constexpr( std::is_invocable_v<
950  Constructor,
951  concepts::construct_nullable_with_empty_t> ) {
952  return Constructor{ }( concepts::construct_nullable_with_empty );
953  } else {
954  return Constructor{ }( );
955  }
956  }
957  } // namespace json_details
958  } // namespace DAW_JSON_VER
959 } // namespace daw::json
#define DAW_JSON_MAKE_REQ_TRAIT(Name,...)
Disable concepts on gcc < 13.3. See https://github.com/beached/daw_json_link/issues/454.
#define DAW_JSON_ENABLEIF_S(...)
typename json_data_contract< T >::type json_data_contract_trait_t
This trait gets us the mapping type from the contract.
JsonParseTypes
The tags used by the parser to determine what parser to call.
@ Tuple
A variant type where the Switcher is based on a submember of the class being parsed.
JsonNullable
Control how json_nullable members are serialized.
DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT(ignore_unknown_members_v, json_data_contract< T >::ignore_unknown_members)
Customization point traits.
DAW_JSON_REQUIRES(boost::describe::has_describe_members< T >::value and use_boost_describe_v< T >) struct json_data_contract< T >
Mapping class for JSON data structures to C++. It must be specialized in order to parse to a user cla...
Default Constructor for a type. It accounts for aggregate types and uses brace construction for them.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25