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