20 #include <daw/daw_algorithm.h>
21 #include <daw/daw_arith_traits.h>
22 #include <daw/daw_cpp_feature_check.h>
23 #include <daw/daw_cxmath.h>
24 #include <daw/daw_likely.h>
25 #include <daw/daw_move.h>
26 #include <daw/daw_simple_array.h>
27 #include <daw/daw_traits.h>
28 #include <daw/daw_utility.h>
29 #include <daw/daw_visit.h>
30 #include <daw/third_party/dragonbox/dragonbox.h>
31 #include <daw/utf8/unchecked.h>
34 #include <daw/stdinc/move_fwd_exch.h>
35 #include <daw/stdinc/tuple_traits.h>
39 #include <string_view>
40 #include <type_traits>
45 namespace json_details {
46 template<
typename WriteableType,
typename Real>
49 WriteableType out_it );
52 namespace json_details::to_strings {
59 if( not has_value( v ) ) {
69 namespace json_details {
71 has_from_string_v, from_string( std::declval<daw::tag_t<T>>( ),
72 std::declval<std::string_view>( ) ) );
75 has_ostream_op_v,
operator<<( std::declval<std::stringstream &>( ),
76 std::declval<T const &>( ) ) );
79 has_istream_op_v,
operator>>( std::declval<std::stringstream &>( ),
80 std::declval<T const &>( ) ) );
93 [[nodiscard]]
static inline auto use_stream( U
const &v ) {
94 std::stringstream ss{ };
96 return std::move( ss ).str( );
102 if constexpr( json_details::is_string_view_like_v<U> ) {
103 return std::string_view( std::data( value ), std::size( value ) );
104 }
else if constexpr( json_details::to_strings::has_to_string_v<U> ) {
105 using json_details::to_strings::to_string;
107 }
else if constexpr( json_details::has_ostream_op_v<U> ) {
108 return use_stream( value );
109 }
else if constexpr( std::is_convertible_v<U, std::string_view> ) {
110 return static_cast<std::string_view
>( value );
111 }
else if constexpr( std::is_convertible_v<U, std::string> ) {
112 return static_cast<std::string
>( value );
113 }
else if constexpr( daw::is_arithmetic_v<U> ) {
115 }
else if constexpr( std::is_enum_v<U> ) {
116 return to_string(
static_cast<std::underlying_type_t<U>
>( value ) );
117 }
else if constexpr( concepts::is_nullable_value_v<U> ) {
118 using value_type = concepts::nullable_value_type_t<U>;
119 if constexpr( json_details::is_string_view_like_v<value_type> ) {
120 if constexpr( std::is_reference_v<DAW_TYPEOF(
123 return daw::string_view(
126 return daw::string_view(
"null" );
130 return std::string( std::data( v ), std::size( v ) );
132 return std::string(
"null", 4 );
134 }
else if constexpr( json_details::to_strings::has_to_string_v<
137 using json_details::to_strings::to_string;
140 using result_t = DAW_TYPEOF(
142 return result_t{
"null" };
144 }
else if constexpr( std::is_convertible_v<value_type,
145 std::string_view> ) {
147 return static_cast<std::string_view
>(
150 return std::string_view{
"null" };
151 }
else if constexpr( std::is_convertible_v<value_type,
154 return static_cast<std::string
>(
157 return std::string(
"null" );
162 return std::string(
"null" );
169 namespace from_json_conv_details {
171 [[nodiscard]]
static inline auto use_stream( std::string_view sv ) {
172 std::stringstream ss{ };
184 if constexpr( std::is_same_v<T, std::string_view> or
185 std::is_same_v<T, std::optional<std::string_view>> ) {
187 }
else if constexpr( json_details::has_from_string_v<T> ) {
188 return from_string( daw::tag<T>, sv );
189 }
else if constexpr( std::is_convertible_v<std::string_view, T> ) {
190 return static_cast<T
>( sv );
191 }
else if constexpr( std::is_convertible_v<std::string, T> ) {
192 return static_cast<T
>(
static_cast<std::string
>( sv ) );
194 static_assert( json_details::has_istream_op_v<T>,
195 "Unsupported type in default to converter. Must "
196 "supply a custom one" );
197 static_assert( std::is_default_constructible_v<T>,
198 "Unsupported type in default to converter. Must "
199 "supply a custom one" );
200 return from_json_conv_details::use_stream<T>( sv );
205 namespace json_details {
207 template<
typename Char>
208 static constexpr char to_nibble_char( Char c ) {
209 auto const u =
static_cast<unsigned>(
static_cast<unsigned char>( c ) );
212 return static_cast<char>( u +
static_cast<unsigned char>(
'0' ) );
214 return static_cast<char>( ( u - 10U ) +
215 static_cast<unsigned char>(
'A' ) );
219 template<
typename WritableType>
220 static constexpr WritableType output_hex( std::uint16_t c,
222 char const nibbles[] = {
'\\',
224 to_nibble_char( ( c >> 12U ) & 0xFU ),
225 to_nibble_char( ( c >> 8U ) & 0xFU ),
226 to_nibble_char( ( c >> 4U ) & 0xFU ),
227 to_nibble_char( c & 0xFU ) };
233 template<
typename WritableType>
234 static constexpr void utf32_to_utf8( std::uint32_t cp,
237 it.put(
static_cast<char>( cp ) );
242 static_cast<char>( ( cp >> 6U ) | 0b11000000U ),
243 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ) };
247 if( cp <= 0xFFFFU ) {
249 static_cast<char>( ( cp >> 12U ) | 0b11100000U ),
250 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
251 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ) };
255 if( cp <= 0x10FFFFU ) {
257 static_cast<char>( ( cp >> 18U ) | 0b11110000U ),
258 static_cast<char>( ( ( cp >> 12U ) & 0b00111111U ) | 0b10000000U ),
259 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
260 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ) };
270 bool do_escape =
false,
272 typename WritableType,
274 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )>
276 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )
277 [[nodiscard]]
static constexpr WritableType
280 EightBitMode != options::EightBitModes::AllowFull or
281 ( WritableType::restricted_string_output ==
282 options::RestrictedStringOutput::OnlyAllow7bitsStrings );
284 using iter = DAW_TYPEOF( std::begin(
container ) );
285 using it_t = utf8::unchecked::iterator<iter>;
286 auto first = it_t( std::begin(
container ) );
287 auto const last = it_t( std::end(
container ) );
288 while( first != last ) {
289 auto const last_it = first;
290 auto const cp = *first++;
291 if( last_it == first ) {
293 if constexpr( WritableType::restricted_string_output ==
298 first = it_t( std::next( first.base( ) ) );
325 it = json_details::output_hex(
static_cast<std::uint16_t
>( cp ),
330 if( cp >= 0x7FU and cp <= 0xFFFFU ) {
331 it = json_details::output_hex(
332 static_cast<std::uint16_t
>( cp ), it );
336 it = json_details::output_hex(
337 static_cast<std::uint16_t
>( 0xD7C0U + ( cp >> 10U ) ), it );
338 it = json_details::output_hex(
339 static_cast<std::uint16_t
>( 0xDC00U + ( cp & 0x3FFU ) ),
344 json_details::utf32_to_utf8( cp, it );
352 static_cast<unsigned char>( c ) <= 0x7FU ),
353 ErrorReason::InvalidStringHighASCII );
362 bool do_escape =
false,
364 typename WriteableType>
365 [[nodiscard]]
static constexpr WriteableType
367 if( ptr ==
nullptr ) {
371 EightBitMode != options::EightBitModes::AllowFull or
372 ( WriteableType::restricted_string_output ==
373 options::RestrictedStringOutput::OnlyAllow7bitsStrings );
376 auto chr_it = utf8::unchecked::iterator<char const *>( ptr );
377 while( *chr_it.base( ) !=
'\0' ) {
378 auto const cp = *chr_it++;
403 it = json_details::output_hex(
static_cast<std::uint16_t
>( cp ),
408 if( cp >= 0x7FU and cp <= 0xFFFFU ) {
409 it = json_details::output_hex(
410 static_cast<std::uint16_t
>( cp ), it );
414 it = json_details::output_hex(
415 static_cast<std::uint16_t
>( 0xD7C0U + ( cp >> 10U ) ), it );
417 static_cast<std::uint16_t
>( 0xDC00U + ( cp & 0x3FFU ) ),
422 json_details::utf32_to_utf8( cp, it );
427 while( *ptr !=
'\0' ) {
430 static_cast<unsigned>( *ptr ) <= 0x7FU ),
431 ErrorReason::InvalidStringHighASCII );
441 bool do_escape =
false,
444 [[nodiscard]]
static constexpr WriteableType
447 return copy_to_iterator<do_escape, EightBitMode>( it,
"null" );
449 return copy_to_iterator<do_escape, EightBitMode>(
455 namespace json_details {
456 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
458 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
459 to_daw_json_string( WriteableType it, parse_to_t
const &value );
461 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
462 [[nodiscard]]
static constexpr WriteableType
463 to_json_string_bool( WriteableType it, parse_to_t
const &value ) {
465 if constexpr( JsonMember::literal_as_string ==
466 options::LiteralAsStringOpt::Always ) {
468 it.write(
"\"true\"" );
470 it.write(
"\"false\"" );
482 template<std::size_t idx,
typename JsonMembers,
typename WriteableType,
484 static constexpr void to_variant_string( WriteableType &it,
485 parse_to_t
const &value ) {
486 if constexpr( idx < std::variant_size_v<parse_to_t> ) {
487 if( value.index( ) != idx ) {
488 to_variant_string<idx + 1, JsonMembers>( it, value );
491 using element_t =
typename JsonMembers::json_elements;
493 typename pack_element<idx, typename element_t::element_map_t>::type;
494 it = to_daw_json_string<JsonMember, JsonMember::expected_type>(
495 it, daw::get_nt<idx>( value ) );
499 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
500 [[nodiscard]]
static inline constexpr WriteableType
501 to_json_string_variant( WriteableType it, parse_to_t
const &value ) {
503 assert( value.index( ) >= 0 );
504 to_variant_string<0, JsonMember>( it, value );
508 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
509 [[nodiscard]]
static inline constexpr WriteableType
510 to_json_string_variant_tagged( WriteableType it,
511 parse_to_t
const &value ) {
513 to_variant_string<0, JsonMember>( it, value );
517 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
518 [[nodiscard]]
static inline constexpr WriteableType
519 to_json_string_variant_intrusive( WriteableType it,
520 parse_to_t
const &value ) {
522 to_variant_string<0, JsonMember>( it, value );
526 template<
typename JsonMember,
typename WriteableType,
typename Optional>
527 [[nodiscard]]
static inline constexpr WriteableType
528 to_json_string_null( WriteableType it, Optional
const &value ) {
530 if constexpr( has_op_bool_v<Optional> ) {
531 if( not
static_cast<bool>( value ) ) {
544 using member_type =
typename JsonMember::member_type;
545 return to_daw_json_string<member_type, member_type::expected_type>(
547 if constexpr( concepts::is_nullable_value_v<Optional> ) {
548 return concepts::nullable_value_traits<Optional>::read( value );
549 }
else if constexpr( json_details::has_op_star_v<Optional> ) {
557 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
558 [[nodiscard]]
static constexpr WriteableType
559 to_json_string_real( WriteableType it, parse_to_t
const &value ) {
562 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
563 "value must be convertible to specified type in class contract" );
565 if constexpr( std::is_floating_point_v<json_result_t<JsonMember>> ) {
566 if( daw::cxmath::is_nan( value ) ) {
567 if constexpr( JsonMember::literal_as_string ==
568 options::LiteralAsStringOpt::Never or
569 JsonMember::allow_number_errors ==
570 options::JsonNumberErrors::None or
571 JsonMember::allow_number_errors ==
572 options::JsonNumberErrors::AllowInf ) {
575 it.write(
"\"NaN\"" );
578 }
else if( daw::cxmath::is_inf( value ) ) {
579 if constexpr( JsonMember::literal_as_string ==
580 options::LiteralAsStringOpt::Never or
581 JsonMember::allow_number_errors ==
582 options::JsonNumberErrors::None or
583 JsonMember::allow_number_errors ==
584 options::JsonNumberErrors::AllowNaN ) {
588 it.write(
"\"-Infinity\"" );
590 it.write(
"\"Infinity\"" );
597 if constexpr( JsonMember::literal_as_string ==
598 options::LiteralAsStringOpt::Always ) {
601 if constexpr( daw::is_floating_point_v<parse_to_t> ) {
602 static_assert(
sizeof( parse_to_t ) <=
sizeof(
double ) );
603 it = to_chars( JsonMember::fp_output_format, value, it );
605 using std::to_string;
606 using to_strings::to_string;
609 if constexpr( JsonMember::literal_as_string ==
610 options::LiteralAsStringOpt::Always ) {
617 using base_int_type_impl = std::underlying_type<T>;
620 using base_int_type_t =
621 typename daw::conditional_t<std::is_enum_v<T>, base_int_type_impl<T>,
622 daw::traits::identity<T>>::type;
624 DAW_ATTRIB_INLINE DAW_CONSTEVAL std::array<char[2], 100>
626 auto result = std::array<char[2], 100>{ };
627 for( std::size_t n = 0;
n < 100; ++
n ) {
629 static_cast<char>( (
n % 10 ) +
static_cast<unsigned char>(
'0' ) );
631 static_cast<char>( (
n / 10 ) +
static_cast<unsigned char>(
'0' ) );
635 inline constexpr auto digits100 = make_digits100( );
638 static constexpr void reverse( T *first, T *last ) {
641 DAW_ASSUME( first and last );
642 DAW_ASSUME( first <= last );
643 auto rpos = last - first;
645 while( lpos < rpos ) {
647 auto tmp = std::move( first[lpos] );
648 first[lpos] = std::move( first[rpos] );
649 first[rpos] = std::move( tmp );
654 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
655 [[nodiscard]]
static constexpr WriteableType
656 to_json_string_signed( WriteableType it, parse_to_t
const &value ) {
659 std::is_convertible_v<parse_to_t, json_base_type_t<JsonMember>>,
660 "value must be convertible to specified type in class contract" );
662 using std::to_string;
663 using to_strings::to_string;
664 using under_type = base_int_type_t<parse_to_t>;
666 if constexpr( std::is_enum_v<parse_to_t> or
667 daw::is_integral_v<parse_to_t> ) {
668 auto v =
static_cast<under_type
>( value );
670 char buff[daw::numeric_limits<under_type>::digits10 + 10]{ };
671 char *num_start = buff;
673 if constexpr( JsonMember::literal_as_string ==
674 options::LiteralAsStringOpt::Always ) {
684 auto const tmp = -
static_cast<std::size_t
>( v % 10 );
686 *ptr++ = digits100[tmp][0];
688 if constexpr( JsonMember::literal_as_string ==
689 options::LiteralAsStringOpt::Always ) {
692 it.copy_buffer( buff, ptr );
701 auto const tmp =
static_cast<std::size_t
>( v % 100 );
703 ptr[0] = digits100[tmp][0];
704 ptr[1] = digits100[tmp][1];
708 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
711 reverse( num_start, ptr );
712 if constexpr( JsonMember::literal_as_string ==
713 options::LiteralAsStringOpt::Always ) {
716 it.copy_buffer( buff, ptr );
719 if constexpr( JsonMember::literal_as_string ==
720 options::LiteralAsStringOpt::Always ) {
725 if constexpr( JsonMember::literal_as_string ==
726 options::LiteralAsStringOpt::Always ) {
733 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
734 [[nodiscard]]
static constexpr WriteableType
735 to_json_string_unsigned( WriteableType it, parse_to_t
const &value ) {
738 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
739 "value must be convertible to specified type in class contract" );
741 using std::to_string;
742 using to_strings::to_string;
743 using under_type = base_int_type_t<parse_to_t>;
744 if constexpr( JsonMember::literal_as_string ==
745 options::LiteralAsStringOpt::Always ) {
748 if constexpr( std::is_same_v<under_type, bool> ) {
749 if(
static_cast<bool>( value ) ) {
754 }
else if constexpr( std::is_enum_v<parse_to_t> or
755 daw::is_integral_v<parse_to_t> ) {
756 auto v =
static_cast<under_type
>( value );
758 if( DAW_UNLIKELY( v == 0 ) ) {
762 char buff[daw::numeric_limits<under_type>::digits10 + 10]{ };
765 auto const tmp =
static_cast<std::size_t
>( v % 100U );
767 ptr[0] = digits100[tmp][0];
768 ptr[1] = digits100[tmp][1];
772 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
774 reverse( buff, ptr );
775 it.copy_buffer( buff, ptr );
781 if constexpr( JsonMember::literal_as_string ==
782 options::LiteralAsStringOpt::Always ) {
790 namespace utils_details {
791 template<
typename Integer>
793 using parse_to_t = Integer;
794 using base_type = parse_to_t;
796 options::LiteralAsStringOpt::Never;
800 template<
typename Integer,
typename WriteableType>
803 static_assert( daw::is_integral_v<Integer> );
805 if constexpr( daw::is_unsigned_v<Integer> ) {
806 return json_details::to_json_string_unsigned<
807 utils_details::number<Integer>>( it, value );
809 return json_details::to_json_string_signed<
810 utils_details::number<Integer>>( it, value );
815 namespace json_details {
816 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
817 [[nodiscard]]
static inline constexpr WriteableType
818 to_json_string_string_raw( WriteableType it, parse_to_t
const &value ) {
821 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
822 "Value must be convertible to specialized type in "
823 "json_data_contract" );
826 JsonMember::eight_bit_mode;
828 if( std::size( value ) > 0U ) {
829 it = utils::copy_to_iterator<false, eight_bit_mode>( it, value );
835 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
836 [[nodiscard]]
static inline constexpr WriteableType
837 to_json_string_string_escaped( WriteableType it,
838 parse_to_t
const &value ) {
841 JsonMember::eight_bit_mode;
843 it = utils::copy_to_iterator<true, eight_bit_mode>( it, value );
849 [[nodiscard]]
static inline constexpr bool
850 is_null( std::optional<T>
const &v ) {
851 return not
static_cast<bool>( v );
855 [[nodiscard]]
static inline constexpr bool is_null( T
const & ) {
859 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
860 [[nodiscard]]
static constexpr WriteableType
861 to_json_string_date( WriteableType it, parse_to_t
const &value ) {
864 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
865 "value must be convertible to specified type in class contract" );
867 using json_details::is_null;
869 if( is_null( value ) ) {
877 if( civil.month < 10 ) {
882 if( civil.day < 10 ) {
887 if( civil.hour < 10 ) {
892 if( civil.minute < 10 ) {
897 if( civil.second < 10 ) {
901 if( civil.nanosecond > 0 ) {
902 while( civil.nanosecond != 0 and civil.nanosecond % 10 == 0 ) {
903 civil.nanosecond /= 10;
912 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
913 [[nodiscard]]
static inline constexpr WriteableType
914 to_json_string_unknown( WriteableType it, parse_to_t
const &value ) {
919 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
920 [[nodiscard]]
static inline constexpr WriteableType
921 to_json_string_class( WriteableType it, parse_to_t
const &value ) {
924 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>> or
925 std::is_same_v<parse_to_t,
926 json_result_t<JsonMember>>,
929 "value must be convertible to specified type in class contract" );
931 if constexpr( has_json_to_json_data_v<parse_to_t> ) {
932 return json_data_contract_trait_t<typename JsonMember::wrapped_type>::
936 typename JsonMember::wrapped_type>::to_json_data( value ),
938 }
else if constexpr( is_json_map_alias_v<parse_to_t> ) {
939 return json_data_contract_trait_t<parse_to_t>::serialize( it, value,
941 }
else if constexpr( std::is_empty_v<parse_to_t> and
942 std::is_default_constructible_v<parse_to_t> and
943 not has_json_data_contract_trait_v<parse_to_t> ) {
947 static_assert( is_submember_tagged_variant_v<parse_to_t>,
948 "Could not find appropriate mapping or to_json_data "
949 "member of json_data_contract" );
950 return json_data_contract_trait_t<parse_to_t>::serialize( it, value );
954 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
955 [[nodiscard]]
static inline constexpr WriteableType
956 to_json_string_custom( WriteableType it, parse_to_t
const &value ) {
959 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
960 "value must be convertible to specified type in class contract" );
962 if constexpr( JsonMember::custom_json_type !=
963 options::JsonCustomTypes::Literal ) {
966 WriteableType,
typename JsonMember::to_converter_t,
967 WriteableType, parse_to_t> ) {
969 it =
typename JsonMember::to_converter_t{ }( it, value );
972 it,
typename JsonMember::to_converter_t{ }( value ) );
978 it,
typename JsonMember::to_converter_t{ }( value ) );
982 template<
typename JsonMember,
typename WriteableType,
985 DAW_ATTRIB_INLINE
constexpr serialization_policy<WriteableType,
986 SerializationOptions>
987 to_daw_json_string_tuple(
988 serialization_policy<WriteableType, SerializationOptions> it,
989 parse_to_t
const &value, std::index_sequence<Is...> ) {
991 auto const to_daw_json_string_help = [&](
auto Idx ) {
992 using index = daw::remove_cvref_t<decltype( Idx )>;
993 using pack_element = tuple_elements_pack<parse_to_t>;
994 using T = std::tuple_element_t<index::value,
995 typename JsonMember::sub_member_list>;
997 it = to_daw_json_string<T, T::expected_type>(
998 it, pack_element::template get<index::value>( value ) );
999 if constexpr( index::value + 1 <
sizeof...( Is ) ) {
1004 (void)to_daw_json_string_help;
1006 daw::empty_t
const expander[]{
1007 ( to_daw_json_string_help( daw::constant_v<Is> ),
1008 daw::empty_t{ } )...,
1015 template<
typename JsonMember,
typename WriteableType,
1017 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1018 SerializationOptions>
1019 to_json_string_tuple(
1020 serialization_policy<WriteableType, SerializationOptions> it,
1021 parse_to_t
const &value ) {
1023 using tuple_t = json_result_t<JsonMember>;
1025 using element_pack = tuple_elements_pack<
typename daw::conditional_t<
1026 is_tuple_v<tuple_t>, daw::traits::identity<tuple_t>,
1027 json_details::identity_parts<tp_from_struct_binding_result_t,
1028 parse_to_t>>::type>;
1031 std::is_convertible_v<parse_to_t, tuple_t>,
1032 "value must be convertible to specified type in class contract" );
1038 it = to_daw_json_string_tuple<JsonMember>(
1039 it, value, std::make_index_sequence<element_pack::size>{ } );
1041 auto value2 = to_tuple_impl( DAW_FWD( value ) );
1043 using value2_t = tp_from_struct_binding_result_t<parse_to_t>;
1044 it = to_daw_json_string_tuple<json_base::json_tuple<value2_t>>(
1045 it, value2, std::make_index_sequence<element_pack::size>{ } );
1048 if constexpr( element_pack::size > 0 ) {
1049 if constexpr( element_pack::size > 0 and
1050 it.output_trailing_comma ==
1051 options::OutputTrailingComma::Yes ) {
1061 is_view_like_v, ( (
void)( std::begin( std::declval<T &>( ) ) ),
1062 (
void)( std::end( std::declval<T &>( ) ) ),
1063 (
void)( std::declval<typename T::value_type>( ) ) ) );
1065 template<
typename JsonMember,
typename WriteableType,
1067 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1068 SerializationOptions>
1069 to_json_string_array(
1070 serialization_policy<WriteableType, SerializationOptions> it,
1071 parse_to_t
const &value ) {
1073 using array_t = json_result_t<JsonMember>;
1074 if constexpr( is_view_like_v<array_t> ) {
1076 std::is_convertible_v<parse_to_t, array_t>,
1077 "value must be convertible to specified type in class contract" );
1080 is_pointer_like_v<array_t>,
1081 "This is a special case for pointer like(T*, unique_ptr<T>, "
1082 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1083 "encode the size of the data with the pointer. Will take any "
1084 "Container like type, but std::span like types work too" );
1086 is_view_like_v<parse_to_t>,
1087 "This is a special case for pointer like(T*, unique_ptr<T>, "
1088 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1089 "encode the size of the data with the pointer. Will take any "
1090 "Container like type, but std::span like types work too" );
1095 auto first = std::begin( value );
1096 auto last = std::end( value );
1097 bool const has_elements = first != last;
1098 while( first != last ) {
1100 it = to_daw_json_string<
typename JsonMember::json_element_t,
1101 JsonMember::json_element_t::expected_type>(
1104 if( first != last ) {
1109 if constexpr( it.output_trailing_comma ==
1110 options::OutputTrailingComma::Yes ) {
1111 if( has_elements ) {
1115 if( has_elements ) {
1122 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1123 [[nodiscard]]
static constexpr WriteableType
1124 to_json_string_sized_array( WriteableType it, parse_to_t
const &value ) {
1125 return to_json_string_array<JsonMember>( it, value );
1128 template<
typename Key,
typename Value>
1130 json_get_key( std::pair<Key, Value>
const &kv ) {
1134 template<
typename Key,
typename Value>
1136 json_get_value( std::pair<Key, Value>
const &kv ) {
1140 template<
typename JsonMember,
typename WriteableType,
1142 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1144 to_json_string_kv_array(
1145 serialization_policy<WriteableType, SerializeOptions> it,
1146 parse_to_t
const &value ) {
1149 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1150 "value must be convertible to specified type in class contract" );
1151 using key_t =
typename JsonMember::json_key_t;
1152 using value_t =
typename JsonMember::json_value_t;
1155 auto first = std::begin( value );
1156 auto last = std::end( value );
1157 bool const has_elements = first != last;
1158 while( first != last ) {
1164 it.write(
"\"", key_t::name,
"\":", it.space );
1166 it = to_daw_json_string<key_t, key_t::expected_type>(
1167 it, json_get_key( *first ) );
1172 it.write(
"\"", value_t::name,
"\":", it.space );
1174 it = to_daw_json_string<value_t, value_t::expected_type>(
1175 it, json_get_value( *first ) );
1178 if constexpr( it.output_trailing_comma ==
1179 options::OutputTrailingComma::Yes ) {
1180 if( has_elements ) {
1187 if( first != last ) {
1192 if constexpr( it.output_trailing_comma ==
1193 options::OutputTrailingComma::Yes ) {
1194 if( has_elements ) {
1198 if( has_elements ) {
1205 template<
typename JsonMember,
typename WriteableType,
1207 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1208 SerializationOptions>
1210 serialization_policy<WriteableType, SerializationOptions> it,
1211 parse_to_t
const &value ) {
1215 auto first = std::begin( value );
1216 auto last = std::end( value );
1217 bool const has_elements = first != last;
1218 while( first != last ) {
1219 auto const &v = *first;
1221 it = to_daw_json_string<
typename JsonMember::json_key_t,
1222 JsonMember::json_key_t::expected_type>(
1223 it, json_get_key( v ) );
1224 it.write(
':', it.space );
1225 it = to_daw_json_string<
typename JsonMember::json_element_t,
1226 JsonMember::json_element_t::expected_type>(
1227 it, json_get_value( v ) );
1229 if( first != last ) {
1234 if constexpr( it.output_trailing_comma ==
1235 options::OutputTrailingComma::Yes ) {
1236 if( has_elements ) {
1240 if( has_elements ) {
1247 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
1248 typename parse_to_t>
1249 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
1250 to_daw_json_string( WriteableType it, parse_to_t
const &value ) {
1251 if constexpr( Tag == JsonParseTypes::Real ) {
1252 return to_json_string_real<JsonMember>( it, value );
1253 }
else if constexpr( Tag == JsonParseTypes::Signed ) {
1254 return to_json_string_signed<JsonMember>( it, value );
1255 }
else if constexpr( Tag == JsonParseTypes::Unsigned ) {
1256 return to_json_string_unsigned<JsonMember>( it, value );
1257 }
else if constexpr( Tag == JsonParseTypes::Null ) {
1258 return to_json_string_null<JsonMember>( it, value );
1259 }
else if constexpr( Tag == JsonParseTypes::Bool ) {
1260 return to_json_string_bool<JsonMember>( it, value );
1261 }
else if constexpr( Tag == JsonParseTypes::StringRaw ) {
1262 return to_json_string_string_raw<JsonMember>( it, value );
1263 }
else if constexpr( Tag == JsonParseTypes::StringEscaped ) {
1264 return to_json_string_string_escaped<JsonMember>( it, value );
1265 }
else if constexpr( Tag == JsonParseTypes::Date ) {
1266 return to_json_string_date<JsonMember>( it, value );
1267 }
else if constexpr( Tag == JsonParseTypes::Custom ) {
1268 return to_json_string_custom<JsonMember>( it, value );
1269 }
else if constexpr( Tag == JsonParseTypes::Class ) {
1270 return to_json_string_class<JsonMember>( it, value );
1271 }
else if constexpr( Tag == JsonParseTypes::KeyValue ) {
1272 return to_json_string_kv<JsonMember>( it, value );
1273 }
else if constexpr( Tag == JsonParseTypes::KeyValueArray ) {
1274 return to_json_string_kv_array<JsonMember>( it, value );
1275 }
else if constexpr( Tag == JsonParseTypes::Array ) {
1276 return to_json_string_array<JsonMember>( it, value );
1277 }
else if constexpr( Tag == JsonParseTypes::SizedArray ) {
1278 return to_json_string_sized_array<JsonMember>( it, value );
1279 }
else if constexpr( Tag == JsonParseTypes::Variant ) {
1280 return to_json_string_variant<JsonMember>( it, value );
1281 }
else if constexpr( Tag == JsonParseTypes::VariantTagged ) {
1282 return to_json_string_variant_tagged<JsonMember>( it, value );
1283 }
else if constexpr( Tag == JsonParseTypes::VariantIntrusive ) {
1284 return to_json_string_variant_intrusive<JsonMember>( it, value );
1285 }
else if constexpr( Tag == JsonParseTypes::Tuple ) {
1286 return to_json_string_tuple<JsonMember>( it, value );
1288 static_assert( Tag == JsonParseTypes::Unknown,
1289 "Unexpected JsonParseType" );
1290 return to_json_string_unknown<JsonMember>( it, value );
1294 template<
typename JsonMember,
typename WriteableType,
typename T>
1295 [[nodiscard]]
static inline constexpr WriteableType
1296 member_to_string( WriteableType it, T
const &value ) {
1297 return to_daw_json_string<JsonMember, JsonMember::expected_type>(
1298 std::move( it ), value );
1302 struct missing_required_mapping_for {};
1306 template<
typename Name>
1307 [[noreturn]] DAW_ATTRIB_NOINLINE
void missing_required_mapping_error( ) {
1308 #if defined( DAW_USE_EXCEPTIONS )
1309 throw missing_required_mapping_for<Name>{ };
1315 template<
typename,
typename...>
1316 struct find_names_in_pack;
1318 template<
typename Needle,
typename... Haystack>
1319 struct find_names_in_pack<Needle,
daw::fwd_pack<Haystack...>> {
1321 static constexpr daw::simple_array<daw::string_view,
1322 sizeof...( Haystack )>
1323 names = { Haystack::name... };
1324 static_assert( ( ( Haystack::name == Needle::name ) or ... ),
1325 "Name must exist" );
1328 static DAW_CONSTEVAL std::size_t find_position( ) {
1330 for( ;
n <
sizeof...( Haystack ); ++
n ) {
1331 if( Needle::name == names[n] ) {
1335 if( n >=
sizeof...( Haystack ) ) {
1336 missing_required_mapping_error<Needle>( );
1341 static constexpr std::size_t value = find_position( );
1344 template<
typename Needle,
typename... Haystack>
1345 inline static constexpr std::size_t find_names_in_pack_v =
1346 find_names_in_pack<Needle, Haystack...>::value;
1348 template<std::size_t pos,
typename JsonMember,
typename NamePack,
1350 typename TpArgs,
typename Value,
typename VisitedMembers>
1351 static constexpr void dependent_member_to_json_str(
1353 serialization_policy<WriteableType, SerializationOptions> it,
1354 TpArgs
const &args, Value
const &v, VisitedMembers &visited_members ) {
1355 if constexpr( not has_dependent_member_v<JsonMember> ) {
1360 (void)visited_members;
1363 using base_member_t =
typename daw::conditional_t<
1364 is_json_nullable_v<JsonMember>,
1365 ident_trait<json_nullable_member_type_t, JsonMember>,
1366 daw::traits::identity<JsonMember>>::type;
1368 using dependent_member = dependent_member_t<base_member_t>;
1372 static_assert( is_a_json_type_v<JsonMember>,
1373 "Unsupported data type" );
1374 if constexpr( is_json_nullable_v<JsonMember> ) {
1375 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1377 if( not get<pos>( args ) ) {
1382 if( daw::algorithm::contains( std::data( visited_members ),
1383 daw::data_end( visited_members ),
1384 dependent_member::name ) ) {
1388 visited_members.push_back( dependent_member::name );
1389 if( not is_first ) {
1394 it.write(
'"', dependent_member::name,
"\":", it.space );
1396 if constexpr( has_switcher_v<base_member_t> ) {
1397 it = member_to_string<dependent_member>(
1398 it,
typename base_member_t::switcher{ }( v ) );
1401 find_names_in_pack_v<dependent_member, NamePack>;
1402 it = member_to_string<dependent_member>( it, get<idx>( args ) );
1408 template<std::size_t pos,
typename JsonMember,
typename WriteableType,
1410 typename Value,
typename Visited>
1411 static inline constexpr void to_json_str(
1413 serialization_policy<WriteableType, SerializationOptions> &it,
1414 Tuple
const &tp, Value
const &, Visited &visited_members ) {
1415 constexpr auto json_member_name = daw::string_view(
1416 std::data( JsonMember::name ), std::size( JsonMember::name ) );
1417 if( daw::algorithm::contains( std::data( visited_members ),
1418 daw::data_end( visited_members ),
1419 json_member_name ) ) {
1422 visited_members.push_back( json_member_name );
1423 static_assert( is_a_json_type_v<JsonMember>,
"Unsupported data type" );
1424 if constexpr( is_json_nullable_v<JsonMember> ) {
1429 if( not is_first ) {
1434 it.write(
'"', JsonMember::name,
"\":", it.space );
1436 it = member_to_string<JsonMember>( std::move( it ), get<pos>( tp ) );
1439 template<std::size_t TupleIdx,
typename JsonMember,
1441 template<
class...>
class Tuple,
typename... Args>
1442 static constexpr void to_json_ordered_str(
1443 std::size_t &array_idx, std::size_t array_size,
1444 serialization_policy<WriteableType, SerializerOptions> &it,
1445 Tuple<Args...>
const &tp ) {
1447 using json_member_type = ordered_member_subtype_t<JsonMember>;
1448 static_assert( is_a_json_type_v<json_member_type>,
1449 "Unsupported data type" );
1453 not is_a_json_tagged_variant_v<json_member_type>,
1454 "JSON tagged variant types are not supported when inside an array "
1455 "as an ordered structure" );
1457 if constexpr( is_an_ordered_member_v<JsonMember> ) {
1458 for( ; array_idx < JsonMember::member_index; ++array_idx ) {
1460 it.write(
"null," );
1464 it = member_to_string<json_member_type>( it, get<TupleIdx>( tp ) );
1466 if( array_idx < array_size ) {
1472 template<
typename WriteableType,
typename Real>
1475 WriteableType out_it ) {
1476 daw::jkj::dragonbox::unsigned_fp_t<Real> dec =
1477 daw::jkj::dragonbox::to_decimal(
1478 value, daw::jkj::dragonbox::policy::sign::ignore );
1481 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1484 auto whole_dig =
static_cast<std::int32_t
>( digits ) + dec.exponent;
1486 auto const br = [&] {
1487 if constexpr( std::is_same_v<Real, float> ) {
1488 return daw::jkj::dragonbox::ieee754_bits( value );
1490 return daw::jkj::dragonbox::ieee754_bits(
1491 static_cast<double>( value ) );
1494 if( dec.significand == 0 ) {
1498 if( br.is_negative( ) ) {
1501 if( fp_output_format == options::FPOutputFormat::Scientific ) {
1505 daw::jkj::dragonbox::to_chars_detail::to_chars( dec, ptr, digits );
1506 out_it.copy_buffer( buff, ptr );
1508 }
else if( fp_output_format == options::FPOutputFormat::Auto ) {
1509 if( ( whole_dig < -4 ) | ( whole_dig > 6 ) ) {
1512 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars( dec, ptr,
1514 out_it.copy_buffer( buff, ptr );
1518 if( dec.exponent < 0 ) {
1519 if( whole_dig < 0 ) {
1520 out_it.write(
"0." );
1524 }
while( whole_dig < 0 );
1530 daw::cxmath::pow10(
static_cast<std::size_t
>( -dec.exponent ) );
1531 auto const p1val = dec.significand / p1pow;
1537 auto const p2val = dec.significand - ( p1val * p1pow );
1541 auto const l10_sig = daw::cxmath::count_digits( dec.significand );
1542 auto const l10_p1val = daw::cxmath::count_digits( p1val );
1543 auto const l10_p2val = daw::cxmath::count_digits( p2val );
1544 auto const extra_zeros = l10_sig - ( l10_p2val + l10_p1val );
1545 for(
int n = 0;
n < extra_zeros; ++
n ) {
1554 while( dec.exponent > 0 ) {
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
#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_CPP23_STATIC_CALL_OP_CONST
#define DAW_JSON_ENABLEIF(...)
#define DAW_JSON_CPP23_STATIC_CALL_OP
This is in addition to the parse policy. Always do a full name match instead of sometimes relying on ...
DAW_ATTRIB_NOINLINE void daw_json_error(ErrorReason reason)
constexpr std::string_view to_string(JsonBaseParseTypes pt)
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.
std::uint32_t json_options_t
constexpr ymdhms time_point_to_civil(std::chrono::time_point< Clock, Duration > const &tp)
RestrictedStringOutput
Allow for restricting the output of strings to 7bits.
LiteralAsStringOpt
Controls the ability to parse numbers that are encoded as strings.
FPOutputFormat
Control the floating point output format.
EightBitModes
Controls whether any string character has the high bit set. If restricted, the member will escape any...
constexpr decltype(auto) get(basic_json_pair< PolicyFlags, Allocator > const &parse_state)
constexpr bool nullable_value_has_value(T const &opt)
Check if nullable value has a value.
constexpr auto const & nullable_value_read(T const &opt)
Read value from a non-empty nullable value.
Container const & container
static constexpr WriteableType copy_to_iterator(WriteableType it, basic_json_value< P, A > const &jv)
static constexpr WriteableType integer_to_string(WriteableType it, Integer const &value)
Customization point traits.
DAW_JSON_REQUIRES(boost::describe::has_describe_members< T >::value and use_boost_describe_v< T >) struct json_data_contract< T >
A non-owning container for arbitrary JSON values that allows movement/iteration through.
constexpr bool is_null() const
Is the JSON value a null literal.
constexpr std::string_view get_string_view() const
Construct a string range of the current value. Strings start inside the quotes.
static auto use_stream(U const &v)
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.