51 namespace json_details {
52 template<
typename WriteableType,
typename Real>
53 static constexpr WriteableType
54 to_chars( options::FPOutputFormat fp_output_format, Real
const &value,
55 WriteableType out_it );
58 namespace json_details::to_strings {
63 [[nodiscard]]
static constexpr auto to_string( std::optional<T>
const &v )
65 if( not has_value( v ) ) {
75 namespace json_details {
77 has_from_string_v, from_string( std::declval<daw::tag_t<T>>( ),
78 std::declval<std::string_view>( ) ) );
81 has_ostream_op_v,
operator<<( std::declval<std::stringstream &>( ),
82 std::declval<T const &>( ) ) );
85 has_istream_op_v,
operator>>( std::declval<std::stringstream &>( ),
86 std::declval<T const &>( ) ) );
99 [[nodiscard]]
static std::string
use_stream( U
const &v ) {
100 std::stringstream ss{ };
102 return std::move( ss ).str( );
108 if constexpr( json_details::is_string_view_like_v<U> ) {
109 return std::string_view( std::data( value ), std::size( value ) );
110 }
else if constexpr( json_details::to_strings::has_to_string_v<U> ) {
111 using json_details::to_strings::to_string;
113 }
else if constexpr( json_details::has_ostream_op_v<U> ) {
114 return use_stream( value );
115 }
else if constexpr( std::is_convertible_v<U, std::string_view> ) {
116 return static_cast<std::string_view
>( value );
117 }
else if constexpr( std::is_convertible_v<U, std::string> ) {
118 return static_cast<std::string
>( value );
119 }
else if constexpr( daw::is_arithmetic_v<U> ) {
121 }
else if constexpr( std::is_enum_v<U> ) {
122 return to_string(
static_cast<std::underlying_type_t<U>
>( value ) );
123 }
else if constexpr( concepts::is_nullable_value_v<U> ) {
124 using value_type = concepts::nullable_value_type_t<U>;
125 if constexpr( json_details::is_string_view_like_v<value_type> ) {
126 if constexpr( std::is_reference_v<DAW_TYPEOF(
127 concepts::nullable_value_read( value ) )> ) {
128 if( concepts::nullable_value_has_value( value ) ) {
129 return daw::string_view(
130 concepts::nullable_value_read( value ) );
132 return daw::string_view(
"null" );
134 if( concepts::nullable_value_has_value( value ) ) {
135 auto const &v = concepts::nullable_value_read( value );
136 return std::string( std::data( v ), std::size( v ) );
138 return std::string(
"null", 4 );
140 }
else if constexpr( json_details::to_strings::has_to_string_v<
142 if( concepts::nullable_value_has_value( value ) ) {
143 using json_details::to_strings::to_string;
144 return to_string( concepts::nullable_value_read( value ) );
146 using result_t = DAW_TYPEOF(
147 to_string( concepts::nullable_value_read( value ) ) );
148 return result_t{
"null" };
150 }
else if constexpr( std::is_convertible_v<value_type,
151 std::string_view> ) {
152 if( concepts::nullable_value_has_value( value ) ) {
153 return static_cast<std::string_view
>(
154 concepts::nullable_value_read( value ) );
156 return std::string_view{
"null" };
157 }
else if constexpr( std::is_convertible_v<value_type,
159 if( concepts::nullable_value_has_value( value ) ) {
160 return static_cast<std::string
>(
161 concepts::nullable_value_read( value ) );
163 return std::string(
"null" );
165 if( concepts::nullable_value_has_value( value ) ) {
166 return use_stream( concepts::nullable_value_has_value( value ) );
168 return std::string(
"null" );
175 namespace from_json_conv_details {
177 [[nodiscard]]
static auto use_stream( std::string_view sv ) {
178 std::stringstream ss{ };
190 if constexpr( std::is_same_v<T, std::string_view> or
191 std::is_same_v<T, std::optional<std::string_view>> ) {
193 }
else if constexpr( json_details::has_from_string_v<T> ) {
194 return from_string( daw::tag<T>, sv );
195 }
else if constexpr( std::is_convertible_v<std::string_view, T> ) {
196 return static_cast<T
>( sv );
197 }
else if constexpr( std::is_convertible_v<std::string, T> ) {
198 return static_cast<T
>(
static_cast<std::string
>( sv ) );
200 static_assert( json_details::has_istream_op_v<T>,
201 "Unsupported type in default to converter. Must "
202 "supply a custom one" );
203 static_assert( std::is_default_constructible_v<T>,
204 "Unsupported type in default to converter. Must "
205 "supply a custom one" );
206 return from_json_conv_details::use_stream<T>( sv );
211 namespace json_details {
213 template<
typename Char>
214 static constexpr char to_nibble_char( Char c ) {
215 auto const u =
static_cast<unsigned>(
static_cast<unsigned char>( c ) );
218 return static_cast<char>( u +
static_cast<unsigned char>(
'0' ) );
220 return static_cast<char>( ( u - 10U ) +
221 static_cast<unsigned char>(
'A' ) );
225 template<
typename WritableType>
226 static constexpr WritableType output_hex( std::uint16_t c,
228 char const nibbles[] = {
'\\',
230 to_nibble_char( ( c >> 12U ) & 0xFU ),
231 to_nibble_char( ( c >> 8U ) & 0xFU ),
232 to_nibble_char( ( c >> 4U ) & 0xFU ),
233 to_nibble_char( c & 0xFU ),
240 template<
typename WritableType>
241 static constexpr void utf32_to_utf8( std::uint32_t cp,
244 it.put(
static_cast<char>( cp ) );
249 static_cast<char>( ( cp >> 6U ) | 0b11000000U ),
250 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
255 if( cp <= 0xFFFFU ) {
257 static_cast<char>( ( cp >> 12U ) | 0b11100000U ),
258 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
259 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
264 if( cp <= 0x10FFFFU ) {
266 static_cast<char>( ( cp >> 18U ) | 0b11110000U ),
267 static_cast<char>( ( ( cp >> 12U ) & 0b00111111U ) | 0b10000000U ),
268 static_cast<char>( ( ( cp >> 6U ) & 0b00111111U ) | 0b10000000U ),
269 static_cast<char>( ( cp & 0b00111111U ) | 0b10000000U ),
280 bool do_escape =
false,
281 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
282 typename WritableType,
283 typename Container DAW_ENABLEIF(
284 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )>
286 daw::traits::is_container_like_v<daw::remove_cvref_t<Container>> )
287 [[nodiscard]]
static constexpr WritableType
289 using restrict_high = std::bool_constant<
290 EightBitMode != options::EightBitModes::AllowFull or
291 ( WritableType::restricted_string_output ==
292 options::RestrictedStringOutput::OnlyAllow7bitsStrings )>;
293 if constexpr( do_escape ) {
294 using iter = DAW_TYPEOF( std::begin(
container ) );
295 using it_t = utf8::unchecked::iterator<iter>;
297 auto first = it_t( std::begin(
container ) );
298 auto const last = it_t( std::end(
container ) );
299 while( first != last ) {
300 auto const last_it = first;
301 auto const cp = *first++;
302 if( last_it == first ) {
304 if constexpr( WritableType::restricted_string_output ==
305 options::RestrictedStringOutput::
309 first = it_t( std::next( first.base( ) ) );
336 it = json_details::output_hex(
static_cast<std::uint16_t
>( cp ),
340 if constexpr( restrict_high::value ) {
341 if( cp >= 0x7FU and cp <= 0xFFFFU ) {
342 it = json_details::output_hex(
343 static_cast<std::uint16_t
>( cp ), it );
347 it = json_details::output_hex(
348 static_cast<std::uint16_t
>( 0xD7C0U + ( cp >> 10U ) ), it );
349 it = json_details::output_hex(
350 static_cast<std::uint16_t
>( 0xDC00U + ( cp & 0x3FFU ) ),
355 json_details::utf32_to_utf8( cp, it );
360 for(
auto c : container ) {
361 if constexpr( restrict_high::value ) {
363 static_cast<unsigned char>( c ) <= 0x7FU ),
364 ErrorReason::InvalidStringHighASCII );
373 bool do_escape =
false,
374 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
375 typename WriteableType>
376 [[nodiscard]]
static constexpr WriteableType
378 if( ptr ==
nullptr ) {
381 using restrict_high = std::bool_constant<
382 EightBitMode != options::EightBitModes::AllowFull or
383 ( WriteableType::restricted_string_output ==
384 options::RestrictedStringOutput::OnlyAllow7bitsStrings )>;
386 if constexpr( do_escape ) {
387 auto chr_it = utf8::unchecked::iterator<char const *>( ptr );
388 while( *chr_it.base( ) !=
'\0' ) {
389 auto const cp = *chr_it++;
414 it = json_details::output_hex(
static_cast<std::uint16_t
>( cp ),
418 if constexpr( restrict_high::value ) {
419 if( cp >= 0x7FU and cp <= 0xFFFFU ) {
420 it = json_details::output_hex(
421 static_cast<std::uint16_t
>( cp ), it );
425 it = json_details::output_hex(
426 static_cast<std::uint16_t
>( 0xD7C0U + ( cp >> 10U ) ), it );
428 static_cast<std::uint16_t
>( 0xDC00U + ( cp & 0x3FFU ) ),
433 json_details::utf32_to_utf8( cp, it );
438 while( *ptr !=
'\0' ) {
439 if constexpr( restrict_high::value ) {
441 static_cast<unsigned>( *ptr ) <= 0x7FU ),
442 ErrorReason::InvalidStringHighASCII );
452 bool do_escape =
false,
453 options::EightBitModes EightBitMode = options::EightBitModes::AllowFull,
455 [[nodiscard]]
static constexpr WriteableType
458 return copy_to_iterator<do_escape, EightBitMode>( it,
"null" );
460 return copy_to_iterator<do_escape, EightBitMode>(
466 namespace json_details {
467 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
469 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
470 to_daw_json_string( WriteableType it, parse_to_t
const &value );
472 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
473 [[nodiscard]]
static constexpr WriteableType
474 to_json_string_bool( WriteableType it, parse_to_t
const &value ) {
476 if constexpr( JsonMember::literal_as_string ==
477 options::LiteralAsStringOpt::Always ) {
479 it.write(
"\"true\"" );
481 it.write(
"\"false\"" );
493 template<std::size_t idx,
typename JsonMembers,
typename WriteableType,
495 static constexpr void to_variant_string( WriteableType &it,
496 parse_to_t
const &value ) {
497 if constexpr( idx < std::variant_size_v<parse_to_t> ) {
498 if( value.index( ) != idx ) {
499 to_variant_string<idx + 1, JsonMembers>( it, value );
502 using element_t =
typename JsonMembers::json_elements;
504 typename pack_element<idx, typename element_t::element_map_t>::type;
505 it = to_daw_json_string<JsonMember, JsonMember::expected_type>(
506 it, daw::get_nt<idx>( value ) );
510 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
511 [[nodiscard]]
static constexpr WriteableType
512 to_json_string_variant( WriteableType it, parse_to_t
const &value ) {
514 assert( value.index( ) >= 0 );
515 to_variant_string<0, JsonMember>( it, value );
519 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
520 [[nodiscard]]
static constexpr WriteableType
521 to_json_string_variant_tagged( WriteableType it,
522 parse_to_t
const &value ) {
524 to_variant_string<0, JsonMember>( it, value );
528 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
529 [[nodiscard]]
static constexpr WriteableType
530 to_json_string_variant_intrusive( WriteableType it,
531 parse_to_t
const &value ) {
533 to_variant_string<0, JsonMember>( it, value );
537 template<
typename JsonMember,
typename WriteableType,
typename Optional>
538 [[nodiscard]]
static constexpr WriteableType
539 to_json_string_null( WriteableType it, Optional
const &value ) {
541 if constexpr( has_op_bool_v<Optional> ) {
542 if( not
static_cast<bool>( value ) ) {
550 if( not concepts::nullable_value_has_value( value ) ) {
555 using member_type =
typename JsonMember::member_type;
556 return to_daw_json_string<member_type, member_type::expected_type>(
558 if constexpr( concepts::is_nullable_value_v<Optional> ) {
559 return concepts::nullable_value_traits<Optional>::read( value );
560 }
else if constexpr( json_details::has_op_star_v<Optional> ) {
568 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
569 [[nodiscard]]
static constexpr WriteableType
570 to_json_string_real( WriteableType it, parse_to_t
const &value ) {
573 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
574 "value must be convertible to specified type in class contract" );
576 if constexpr( std::is_floating_point_v<json_result_t<JsonMember>> ) {
577 if( daw::cxmath::is_nan( value ) ) {
578 if constexpr( JsonMember::literal_as_string ==
579 options::LiteralAsStringOpt::Never or
580 JsonMember::allow_number_errors ==
581 options::JsonNumberErrors::None or
582 JsonMember::allow_number_errors ==
583 options::JsonNumberErrors::AllowInf ) {
586 it.write(
"\"NaN\"" );
589 }
else if( daw::cxmath::is_inf( value ) ) {
590 if constexpr( JsonMember::literal_as_string ==
591 options::LiteralAsStringOpt::Never or
592 JsonMember::allow_number_errors ==
593 options::JsonNumberErrors::None or
594 JsonMember::allow_number_errors ==
595 options::JsonNumberErrors::AllowNaN ) {
599 it.write(
"\"-Infinity\"" );
601 it.write(
"\"Infinity\"" );
608 if constexpr( JsonMember::literal_as_string ==
609 options::LiteralAsStringOpt::Always ) {
612 if constexpr( daw::is_floating_point_v<parse_to_t> ) {
613 static_assert(
sizeof( parse_to_t ) <=
sizeof(
double ) );
614 it = to_chars( JsonMember::fp_output_format, value, it );
616 using std::to_string;
617 using to_strings::to_string;
618 it = utils::copy_to_iterator( it,
to_string( value ) );
620 if constexpr( JsonMember::literal_as_string ==
621 options::LiteralAsStringOpt::Always ) {
628 using base_int_type_impl = std::underlying_type<T>;
631 using base_int_type_t =
632 typename daw::conditional_t<std::is_enum_v<T>, base_int_type_impl<T>,
633 daw::traits::identity<T>>::type;
635 DAW_ATTRIB_INLINE DAW_CONSTEVAL std::array<char[2], 100>
637 auto result = std::array<char[2], 100>{ };
638 for( std::size_t n = 0;
n < 100; ++
n ) {
640 static_cast<char>( (
n % 10 ) +
static_cast<unsigned char>(
'0' ) );
642 static_cast<char>( (
n / 10 ) +
static_cast<unsigned char>(
'0' ) );
646 inline constexpr auto digits100 = make_digits100( );
649 static constexpr void reverse( T *first, T *last ) {
652 DAW_ASSUME( first and last );
653 DAW_ASSUME( first <= last );
654 auto rpos = last - first;
656 while( lpos < rpos ) {
658 auto tmp = std::move( first[lpos] );
659 first[lpos] = std::move( first[rpos] );
660 first[rpos] = std::move( tmp );
665 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
666 [[nodiscard]]
static constexpr WriteableType
667 to_json_string_signed( WriteableType it, parse_to_t
const &value ) {
670 std::is_convertible_v<parse_to_t, json_base_type_t<JsonMember>>,
671 "value must be convertible to specified type in class contract" );
673 using std::to_string;
674 using to_strings::to_string;
675 using under_type = base_int_type_t<parse_to_t>;
677 if constexpr( std::is_enum_v<parse_to_t> or
678 daw::is_integral_v<parse_to_t> ) {
679 auto v =
static_cast<under_type
>( value );
681 char buff[daw::numeric_limits<under_type>::digits10 + 10]{ };
682 char *num_start = buff;
684 if constexpr( JsonMember::literal_as_string ==
685 options::LiteralAsStringOpt::Always ) {
695 auto const tmp = -
static_cast<std::size_t
>( v % 10 );
697 *ptr++ = digits100[tmp][0];
699 if constexpr( JsonMember::literal_as_string ==
700 options::LiteralAsStringOpt::Always ) {
703 it.copy_buffer( buff, ptr );
712 auto const tmp =
static_cast<std::size_t
>( v % 100 );
714 ptr[0] = digits100[tmp][0];
715 ptr[1] = digits100[tmp][1];
719 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
722 reverse( num_start, ptr );
723 if constexpr( JsonMember::literal_as_string ==
724 options::LiteralAsStringOpt::Always ) {
727 it.copy_buffer( buff, ptr );
730 if constexpr( JsonMember::literal_as_string ==
731 options::LiteralAsStringOpt::Always ) {
735 it = utils::copy_to_iterator( it,
to_string( value ) );
736 if constexpr( JsonMember::literal_as_string ==
737 options::LiteralAsStringOpt::Always ) {
744 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
745 [[nodiscard]]
static constexpr WriteableType
746 to_json_string_unsigned( WriteableType it, parse_to_t
const &value ) {
749 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
750 "value must be convertible to specified type in class contract" );
752 using std::to_string;
753 using to_strings::to_string;
754 using under_type = base_int_type_t<parse_to_t>;
755 if constexpr( JsonMember::literal_as_string ==
756 options::LiteralAsStringOpt::Always ) {
759 if constexpr( std::is_same_v<under_type, bool> ) {
760 if(
static_cast<bool>( value ) ) {
765 }
else if constexpr( std::is_enum_v<parse_to_t> or
766 daw::is_integral_v<parse_to_t> ) {
767 auto v =
static_cast<under_type
>( value );
769 if( DAW_UNLIKELY( v == 0 ) ) {
773 char buff[daw::numeric_limits<under_type>::digits10 + 10]{ };
776 auto const tmp =
static_cast<std::size_t
>( v % 100U );
778 ptr[0] = digits100[tmp][0];
779 ptr[1] = digits100[tmp][1];
783 *ptr++ =
static_cast<char>(
'0' +
static_cast<char>( v ) );
785 reverse( buff, ptr );
786 it.copy_buffer( buff, ptr );
790 it = utils::copy_to_iterator( it,
to_string( value ) );
792 if constexpr( JsonMember::literal_as_string ==
793 options::LiteralAsStringOpt::Always ) {
801 namespace utils_details {
802 template<
typename Integer>
804 using parse_to_t = Integer;
805 using base_type = parse_to_t;
806 static constexpr options::LiteralAsStringOpt literal_as_string =
807 options::LiteralAsStringOpt::Never;
811 template<
typename Integer,
typename WriteableType>
813 Integer
const &value ) {
814 static_assert( daw::is_integral_v<Integer> );
816 if constexpr( daw::is_unsigned_v<Integer> ) {
817 return json_details::to_json_string_unsigned<
818 utils_details::number<Integer>>( it, value );
820 return json_details::to_json_string_signed<
821 utils_details::number<Integer>>( it, value );
826 namespace json_details {
827 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
828 [[nodiscard]]
static constexpr WriteableType
829 to_json_string_string_raw( WriteableType it, parse_to_t
const &value ) {
832 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
833 "Value must be convertible to specialized type in "
834 "json_data_contract" );
837 if( std::size( value ) > 0U ) {
838 it = utils::copy_to_iterator<false, JsonMember::eight_bit_mode>(
845 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
846 [[nodiscard]]
static constexpr WriteableType
847 to_json_string_string_escaped( WriteableType it,
848 parse_to_t
const &value ) {
851 it = utils::copy_to_iterator<true, JsonMember::eight_bit_mode>( it,
858 [[nodiscard]]
static constexpr bool is_null( std::optional<T>
const &v ) {
859 return not
static_cast<bool>( v );
863 [[nodiscard]]
static constexpr bool is_null( T
const & ) {
867 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
868 [[nodiscard]]
static constexpr WriteableType
869 to_json_string_date( WriteableType it, parse_to_t
const &value ) {
872 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
873 "value must be convertible to specified type in class contract" );
875 using json_details::is_null;
877 if( is_null( value ) ) {
882 datetime::ymdhms civil = datetime::time_point_to_civil( value );
883 it = utils::integer_to_string( it, civil.year );
885 if( civil.month < 10 ) {
888 it = utils::integer_to_string( it, civil.month );
890 if( civil.day < 10 ) {
893 it = utils::integer_to_string( it, civil.day );
895 if( civil.hour < 10 ) {
898 it = utils::integer_to_string( it, civil.hour );
900 if( civil.minute < 10 ) {
903 it = utils::integer_to_string( it, civil.minute );
905 if( civil.second < 10 ) {
908 it = utils::integer_to_string( it, civil.second );
909 if( civil.nanosecond > 0 ) {
910 while( civil.nanosecond != 0 and civil.nanosecond % 10 == 0 ) {
911 civil.nanosecond /= 10;
914 it = utils::integer_to_string( it, civil.nanosecond );
920 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
921 [[nodiscard]]
static constexpr WriteableType
922 to_json_string_unknown( WriteableType it, parse_to_t
const &value ) {
924 return utils::copy_to_iterator( it, value );
927 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
928 [[nodiscard]]
static constexpr WriteableType
929 to_json_string_class( WriteableType it, parse_to_t
const &value ) {
932 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>> or
933 std::is_same_v<parse_to_t,
934 json_result_t<JsonMember>>,
937 "value must be convertible to specified type in class contract" );
939 if constexpr( has_json_to_json_data_v<parse_to_t> ) {
940 return json_data_contract_trait_t<typename JsonMember::wrapped_type>::
944 typename JsonMember::wrapped_type>::to_json_data( value ),
946 }
else if constexpr( is_json_map_alias_v<parse_to_t> ) {
947 return json_data_contract_trait_t<parse_to_t>::serialize(
949 }
else if constexpr( std::is_empty_v<parse_to_t> and
950 std::is_default_constructible_v<parse_to_t> and
951 not has_json_data_contract_trait_v<parse_to_t> ) {
955 static_assert( is_submember_tagged_variant_v<parse_to_t>,
956 "Could not find appropriate mapping or to_json_data "
957 "member of json_data_contract" );
958 return json_data_contract_trait_t<parse_to_t>::serialize( it, value );
962 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
963 [[nodiscard]]
static constexpr WriteableType
964 to_json_string_custom( WriteableType it, parse_to_t
const &value ) {
967 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
968 "value must be convertible to specified type in class contract" );
970 if constexpr( JsonMember::custom_json_type !=
971 options::JsonCustomTypes::Literal ) {
974 if constexpr( daw::is_callable_r_v<
976 typename JsonMember::to_converter_t,
979 it =
typename JsonMember::to_converter_t{ }( it, value );
981 it = utils::copy_to_iterator(
982 it,
typename JsonMember::to_converter_t{ }( value ) );
987 return utils::copy_to_iterator(
988 it,
typename JsonMember::to_converter_t{ }( value ) );
992 template<
typename JsonMember,
typename WriteableType,
995 DAW_ATTRIB_INLINE
constexpr serialization_policy<WriteableType,
996 SerializationOptions>
997 to_daw_json_string_tuple(
998 serialization_policy<WriteableType, SerializationOptions> it,
999 parse_to_t
const &value, std::index_sequence<Is...> ) {
1001 auto const to_daw_json_string_help = [&](
auto Idx ) {
1002 using index = daw::remove_cvref_t<
decltype( Idx )>;
1003 using pack_element = tuple_elements_pack<parse_to_t>;
1004 using T = std::tuple_element_t<index::value,
1005 typename JsonMember::sub_member_list>;
1007 it = to_daw_json_string<T, T::expected_type>(
1008 it, pack_element::template get<index::value>( value ) );
1009 if constexpr( index::value + 1 <
sizeof...( Is ) ) {
1014 (void)to_daw_json_string_help;
1016 daw::empty_t
const expander[]{
1017 ( to_daw_json_string_help( daw::constant_v<Is> ),
1018 daw::empty_t{ } )...,
1025 template<
typename JsonMember,
typename WriteableType,
1027 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1028 SerializationOptions>
1029 to_json_string_tuple(
1030 serialization_policy<WriteableType, SerializationOptions> it,
1031 parse_to_t
const &value ) {
1033 using tuple_t = json_result_t<JsonMember>;
1035 using element_pack = tuple_elements_pack<
typename daw::conditional_t<
1036 is_tuple_v<tuple_t>,
1037 daw::traits::identity<tuple_t>,
1038 json_details::identity_parts<tp_from_struct_binding_result_t,
1039 parse_to_t>>::type>;
1042 std::is_convertible_v<parse_to_t, tuple_t>,
1043 "value must be convertible to specified type in class contract" );
1048 if constexpr( is_tuple_v<tuple_t> ) {
1049 it = to_daw_json_string_tuple<JsonMember>(
1050 it, value, std::make_index_sequence<element_pack::size>{ } );
1052 auto value2 = to_tuple_impl( DAW_FWD( value ) );
1054 using value2_t = tp_from_struct_binding_result_t<parse_to_t>;
1055 it = to_daw_json_string_tuple<json_base::json_tuple<value2_t>>(
1056 it, value2, std::make_index_sequence<element_pack::size>{ } );
1059 if constexpr( element_pack::size > 0 ) {
1060 if constexpr( element_pack::size > 0 and
1061 it.output_trailing_comma ==
1062 options::OutputTrailingComma::Yes ) {
1072 is_view_like_v, ( (
void)( std::begin( std::declval<T &>( ) ) ),
1073 (
void)( std::end( std::declval<T &>( ) ) ),
1074 (
void)( std::declval<typename T::value_type>( ) ) ) );
1076 template<
typename JsonMember,
typename WriteableType,
1078 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1079 SerializationOptions>
1080 to_json_string_array(
1081 serialization_policy<WriteableType, SerializationOptions> it,
1082 parse_to_t
const &value ) {
1084 using array_t = json_result_t<JsonMember>;
1085 if constexpr( is_view_like_v<array_t> ) {
1087 std::is_convertible_v<parse_to_t, array_t>,
1088 "value must be convertible to specified type in class contract" );
1091 is_pointer_like_v<array_t>,
1092 "This is a special case for pointer like(T*, unique_ptr<T>, "
1093 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1094 "encode the size of the data with the pointer. Will take any "
1095 "Container like type, but std::span like types work too" );
1097 is_view_like_v<parse_to_t>,
1098 "This is a special case for pointer like(T*, unique_ptr<T>, "
1099 "shared_ptr<T>) arrays. In the to_json_data it is required to "
1100 "encode the size of the data with the pointer. Will take any "
1101 "Container like type, but std::span like types work too" );
1106 auto first = std::begin( value );
1107 auto last = std::end( value );
1108 bool const has_elements = first != last;
1109 while( first != last ) {
1111 it = to_daw_json_string<
typename JsonMember::json_element_t,
1112 JsonMember::json_element_t::expected_type>(
1115 if( first != last ) {
1120 if constexpr( it.output_trailing_comma ==
1121 options::OutputTrailingComma::Yes ) {
1122 if( has_elements ) {
1126 if( has_elements ) {
1133 template<
typename JsonMember,
typename WriteableType,
typename parse_to_t>
1134 [[nodiscard]]
static constexpr WriteableType
1135 to_json_string_sized_array( WriteableType it, parse_to_t
const &value ) {
1136 return to_json_string_array<JsonMember>( it, value );
1139 template<
typename Key,
typename Value>
1140 static constexpr Key
const &
1141 json_get_key( std::pair<Key, Value>
const &kv ) {
1145 template<
typename Key,
typename Value>
1146 static constexpr Value
const &
1147 json_get_value( std::pair<Key, Value>
const &kv ) {
1151 template<
typename JsonMember,
typename WriteableType,
1153 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1155 to_json_string_kv_array(
1156 serialization_policy<WriteableType, SerializeOptions> it,
1157 parse_to_t
const &value ) {
1160 std::is_convertible_v<parse_to_t, json_result_t<JsonMember>>,
1161 "value must be convertible to specified type in class contract" );
1162 using key_t =
typename JsonMember::json_key_t;
1163 using value_t =
typename JsonMember::json_value_t;
1166 auto first = std::begin( value );
1167 auto last = std::end( value );
1168 bool const has_elements = first != last;
1169 while( first != last ) {
1175 it.write(
"\"", key_t::name,
"\":", it.space );
1177 it = to_daw_json_string<key_t, key_t::expected_type>(
1178 it, json_get_key( *first ) );
1183 it.write(
"\"", value_t::name,
"\":", it.space );
1185 it = to_daw_json_string<value_t, value_t::expected_type>(
1186 it, json_get_value( *first ) );
1189 if constexpr( it.output_trailing_comma ==
1190 options::OutputTrailingComma::Yes ) {
1191 if( has_elements ) {
1198 if( first != last ) {
1203 if constexpr( it.output_trailing_comma ==
1204 options::OutputTrailingComma::Yes ) {
1205 if( has_elements ) {
1209 if( has_elements ) {
1216 template<
typename JsonMember,
typename WriteableType,
1218 [[nodiscard]]
static constexpr serialization_policy<WriteableType,
1219 SerializationOptions>
1221 serialization_policy<WriteableType, SerializationOptions> it,
1222 parse_to_t
const &value ) {
1226 auto first = std::begin( value );
1227 auto last = std::end( value );
1228 bool const has_elements = first != last;
1229 while( first != last ) {
1230 auto const &v = *first;
1232 it = to_daw_json_string<
typename JsonMember::json_key_t,
1233 JsonMember::json_key_t::expected_type>(
1234 it, json_get_key( v ) );
1235 it.write(
':', it.space );
1236 it = to_daw_json_string<
typename JsonMember::json_element_t,
1237 JsonMember::json_element_t::expected_type>(
1238 it, json_get_value( v ) );
1240 if( first != last ) {
1245 if constexpr( it.output_trailing_comma ==
1246 options::OutputTrailingComma::Yes ) {
1247 if( has_elements ) {
1251 if( has_elements ) {
1258 template<
typename JsonMember,
JsonParseTypes Tag,
typename WriteableType,
1259 typename parse_to_t>
1260 [[nodiscard]] DAW_ATTRIB_INLINE
static constexpr WriteableType
1261 to_daw_json_string( WriteableType it, parse_to_t
const &value ) {
1262 if constexpr( Tag == JsonParseTypes::Real ) {
1263 return to_json_string_real<JsonMember>( it, value );
1264 }
else if constexpr( Tag == JsonParseTypes::Signed ) {
1265 return to_json_string_signed<JsonMember>( it, value );
1266 }
else if constexpr( Tag == JsonParseTypes::Unsigned ) {
1267 return to_json_string_unsigned<JsonMember>( it, value );
1268 }
else if constexpr( Tag == JsonParseTypes::Null ) {
1269 return to_json_string_null<JsonMember>( it, value );
1270 }
else if constexpr( Tag == JsonParseTypes::Bool ) {
1271 return to_json_string_bool<JsonMember>( it, value );
1272 }
else if constexpr( Tag == JsonParseTypes::StringRaw ) {
1273 return to_json_string_string_raw<JsonMember>( it, value );
1274 }
else if constexpr( Tag == JsonParseTypes::StringEscaped ) {
1275 return to_json_string_string_escaped<JsonMember>( it, value );
1276 }
else if constexpr( Tag == JsonParseTypes::Date ) {
1277 return to_json_string_date<JsonMember>( it, value );
1278 }
else if constexpr( Tag == JsonParseTypes::Custom ) {
1279 return to_json_string_custom<JsonMember>( it, value );
1280 }
else if constexpr( Tag == JsonParseTypes::Class ) {
1281 return to_json_string_class<JsonMember>( it, value );
1282 }
else if constexpr( Tag == JsonParseTypes::KeyValue ) {
1283 return to_json_string_kv<JsonMember>( it, value );
1284 }
else if constexpr( Tag == JsonParseTypes::KeyValueArray ) {
1285 return to_json_string_kv_array<JsonMember>( it, value );
1286 }
else if constexpr( Tag == JsonParseTypes::Array ) {
1287 return to_json_string_array<JsonMember>( it, value );
1288 }
else if constexpr( Tag == JsonParseTypes::SizedArray ) {
1289 return to_json_string_sized_array<JsonMember>( it, value );
1290 }
else if constexpr( Tag == JsonParseTypes::Variant ) {
1291 return to_json_string_variant<JsonMember>( it, value );
1292 }
else if constexpr( Tag == JsonParseTypes::VariantTagged ) {
1293 return to_json_string_variant_tagged<JsonMember>( it, value );
1294 }
else if constexpr( Tag == JsonParseTypes::VariantIntrusive ) {
1295 return to_json_string_variant_intrusive<JsonMember>( it, value );
1296 }
else if constexpr( Tag == JsonParseTypes::Tuple ) {
1297 return to_json_string_tuple<JsonMember>( it, value );
1299 static_assert( Tag == JsonParseTypes::Unknown,
1300 "Unexpected JsonParseType" );
1301 return to_json_string_unknown<JsonMember>( it, value );
1305 template<
typename JsonMember,
typename WriteableType,
typename T>
1306 [[nodiscard]]
static constexpr WriteableType
1307 member_to_string( WriteableType it, T
const &value ) {
1308 return to_daw_json_string<JsonMember, JsonMember::expected_type>(
1309 std::move( it ), value );
1313 struct missing_required_mapping_for {};
1317 template<
typename Name>
1318 [[noreturn]] DAW_ATTRIB_NOINLINE
void missing_required_mapping_error( ) {
1319#if defined( DAW_USE_EXCEPTIONS )
1320 throw missing_required_mapping_for<Name>{ };
1326 template<
typename,
typename...>
1327 struct find_names_in_pack;
1329 template<
typename Needle,
typename... Haystack>
1330 struct find_names_in_pack<Needle,
daw::fwd_pack<Haystack...>> {
1332 static constexpr daw::simple_array<daw::string_view,
1333 sizeof...( Haystack )>
1334 names = { Haystack::name... };
1335 static_assert( ( ( Haystack::name == Needle::name ) or ... ),
1336 "Name must exist" );
1339 static DAW_CONSTEVAL std::size_t find_position( ) {
1341 for( ;
n <
sizeof...( Haystack ); ++
n ) {
1342 if( Needle::name == names[n] ) {
1346 if( n >=
sizeof...( Haystack ) ) {
1347 missing_required_mapping_error<Needle>( );
1352 static constexpr std::size_t value = find_position( );
1355 template<
typename Needle,
typename... Haystack>
1356 inline static constexpr std::size_t find_names_in_pack_v =
1357 find_names_in_pack<Needle, Haystack...>::value;
1359 template<std::size_t pos,
typename JsonMember,
typename NamePack,
1361 typename TpArgs,
typename Value,
typename VisitedMembers>
1362 static constexpr void dependent_member_to_json_str(
1364 serialization_policy<WriteableType, SerializationOptions> it,
1365 TpArgs
const &args, Value
const &v, VisitedMembers &visited_members ) {
1366 if constexpr( not has_dependent_member_v<JsonMember> ) {
1371 (void)visited_members;
1374 using base_member_t =
typename daw::conditional_t<
1375 is_json_nullable_v<JsonMember>,
1376 ident_trait<json_nullable_member_type_t, JsonMember>,
1377 daw::traits::identity<JsonMember>>::type;
1379 using dependent_member = dependent_member_t<base_member_t>;
1383 static_assert( is_a_json_type_v<JsonMember>,
1384 "Unsupported data type" );
1385 if constexpr( is_json_nullable_v<JsonMember> ) {
1386 if constexpr( JsonMember::nullable == JsonNullable::Nullable ) {
1388 if( not get<pos>( args ) ) {
1393 if( daw::algorithm::contains( std::data( visited_members ),
1394 daw::data_end( visited_members ),
1395 dependent_member::name ) ) {
1399 visited_members.push_back( dependent_member::name );
1400 if( not is_first ) {
1405 it.write(
'"', dependent_member::name,
"\":", it.space );
1407 if constexpr( has_switcher_v<base_member_t> ) {
1408 it = member_to_string<dependent_member>(
1409 it,
typename base_member_t::switcher{ }( v ) );
1412 daw::constant<find_names_in_pack_v<dependent_member, NamePack>>;
1414 member_to_string<dependent_member>( it, get<idx::value>( args ) );
1420 template<std::size_t pos,
typename JsonMember,
typename WriteableType,
1422 typename Value,
typename Visited>
1423 static constexpr void to_json_str(
1425 serialization_policy<WriteableType, SerializationOptions> &it,
1426 Tuple
const &tp, Value
const &, Visited &visited_members ) {
1427 DAW_CPP23_STATIC_LOCAL
constexpr auto json_member_name =
1428 daw::string_view( std::data( JsonMember::name ),
1429 std::size( JsonMember::name ) );
1430 if( daw::algorithm::contains( std::data( visited_members ),
1431 daw::data_end( visited_members ),
1432 json_member_name ) ) {
1435 visited_members.push_back( json_member_name );
1436 static_assert( is_a_json_type_v<JsonMember>,
"Unsupported data type" );
1437 if constexpr( is_json_nullable_v<JsonMember> ) {
1438 if( not concepts::nullable_value_has_value( get<pos>( tp ) ) ) {
1442 if( not is_first ) {
1447 it.write(
'"', JsonMember::name,
"\":", it.space );
1449 it = member_to_string<JsonMember>( std::move( it ), get<pos>( tp ) );
1452 template<std::size_t TupleIdx,
typename JsonMember,
1454 template<
class...>
class Tuple,
typename... Args>
1455 static constexpr void to_json_ordered_str(
1456 std::size_t &array_idx, std::size_t array_size,
1457 serialization_policy<WriteableType, SerializerOptions> &it,
1458 Tuple<Args...>
const &tp ) {
1460 using json_member_type = ordered_member_subtype_t<JsonMember>;
1461 static_assert( is_a_json_type_v<json_member_type>,
1462 "Unsupported data type" );
1466 not is_a_json_tagged_variant_v<json_member_type>,
1467 "JSON tagged variant types are not supported when inside an array "
1468 "as an ordered structure" );
1470 if constexpr( is_an_ordered_member_v<JsonMember> ) {
1471 for( ; array_idx < JsonMember::member_index; ++array_idx ) {
1473 it.write(
"null," );
1477 it = member_to_string<json_member_type>( it, get<TupleIdx>( tp ) );
1479 if( array_idx < array_size ) {
1485 template<
typename WriteableType,
typename Real>
1486 static constexpr WriteableType
1487 to_chars( options::FPOutputFormat fp_output_format, Real
const &value,
1488 WriteableType out_it ) {
1489 daw::jkj::dragonbox::unsigned_fp_t<Real> dec =
1490 daw::jkj::dragonbox::to_decimal(
1491 value, daw::jkj::dragonbox::policy::sign::ignore );
1493 auto const digit_values =
1494 daw::jkj::dragonbox::to_chars_detail::decimal_length(
1498 static_cast<std::int32_t
>( digit_values ) + dec.exponent;
1500 auto const br = [&] {
1501 if constexpr( std::is_same_v<Real, float> ) {
1502 return daw::jkj::dragonbox::ieee754_bits( value );
1504 return daw::jkj::dragonbox::ieee754_bits(
1505 static_cast<double>( value ) );
1508 if( dec.significand == 0 ) {
1512 if( br.is_negative( ) ) {
1515 if( fp_output_format == options::FPOutputFormat::Scientific ) {
1518 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars(
1519 dec, ptr, digit_values );
1520 out_it.copy_buffer( buff, ptr );
1522 }
else if( fp_output_format == options::FPOutputFormat::Auto ) {
1523 if( ( whole_dig < -4 ) | ( whole_dig > 6 ) ) {
1526 ptr = daw::jkj::dragonbox::to_chars_detail::to_chars(
1527 dec, ptr, digit_values );
1528 out_it.copy_buffer( buff, ptr );
1532 if( dec.exponent < 0 ) {
1533 if( whole_dig < 0 ) {
1534 out_it.write(
"0." );
1538 }
while( whole_dig < 0 );
1539 out_it = utils::integer_to_string( out_it, dec.significand );
1544 daw::cxmath::pow10(
static_cast<std::size_t
>( -dec.exponent ) );
1545 auto const p1val = dec.significand / p1pow;
1546 out_it = utils::integer_to_string( out_it, p1val );
1551 auto const p2val = dec.significand - ( p1val * p1pow );
1555 auto const l10_sig = daw::cxmath::count_digits( dec.significand );
1556 auto const l10_p1val = daw::cxmath::count_digits( p1val );
1557 auto const l10_p2val = daw::cxmath::count_digits( p2val );
1558 auto const extra_zeros = l10_sig - ( l10_p2val + l10_p1val );
1559 for(
int n = 0;
n < extra_zeros; ++
n ) {
1563 out_it = utils::integer_to_string( out_it, p2val );
1566 out_it = utils::integer_to_string( out_it, dec.significand );
1568 while( dec.exponent > 0 ) {