DAW JSON Link
Loading...
Searching...
No Matches
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"
19#include "daw_json_traits.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
42namespace 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>
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>
310
311 template<typename T, typename FromJsonConverter = use_default,
312 typename ToJsonConverter = use_default,
315
316 template<typename Variant, typename JsonElements = use_default,
317 typename Constructor = use_default>
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>
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>
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>
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_TYPE_ALIAS_TRAIT(Name,...)
#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(...)
#define DAW_JSON_REQUIRES(...)
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.
Customization point traits.
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:20