13 #include <daw/daw_utility.h>
23 template<
typename WriteableType>
24 static inline constexpr WriteableType
25 output_kv( WriteableType it, std::string_view key,
26 std::string_view value ) {
27 it.write( key,
":", it.space, value );
31 namespace json_details {
32 template<
typename JsonMember,
bool is_root =
false,
33 typename WriteableType>
34 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Bool>,
35 WriteableType out_it ) {
37 if constexpr( not is_root ) {
40 out_it.next_member( );
42 out_it = utils::output_kv( out_it, R
"("type")", R"("boolean")" );
43 if constexpr( not is_root ) {
46 out_it.next_member( );
47 if constexpr( not is_root ) {
53 template<
typename JsonMember,
bool is_root =
false,
54 typename WriteableType>
55 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Custom>,
56 WriteableType out_it ) {
59 static_assert( JsonMember::custom_json_type ==
60 options::JsonCustomTypes::String );
61 if constexpr( not is_root ) {
64 out_it.next_member( );
66 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
67 if constexpr( not is_root ) {
70 out_it.next_member( );
71 if constexpr( not is_root ) {
77 template<
typename JsonMember,
bool is_root =
false,
78 typename WriteableType>
79 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Date>,
80 WriteableType out_it ) {
82 if constexpr( not is_root ) {
85 out_it.next_member( );
87 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
89 out_it.next_member( );
90 out_it = utils::output_kv( out_it, R
"("format")", R"("date-time")" );
91 if constexpr( not is_root ) {
94 out_it.next_member( );
95 if constexpr( not is_root ) {
101 template<
typename JsonMember,
bool is_root =
false,
102 typename WriteableType>
103 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Real>,
104 WriteableType out_it ) {
106 if constexpr( not is_root ) {
108 out_it.add_indent( );
109 out_it.next_member( );
111 out_it = utils::output_kv( out_it, R
"("type")", R"("number")" );
112 if constexpr( not is_root ) {
113 out_it.del_indent( );
115 out_it.next_member( );
116 if constexpr( not is_root ) {
122 template<
typename JsonMember,
bool is_root =
false,
123 typename WriteableType>
124 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Signed>,
125 WriteableType out_it ) {
127 if constexpr( not is_root ) {
129 out_it.add_indent( );
130 out_it.next_member( );
132 out_it = utils::output_kv( out_it, R
"("type")", R"("integer")" );
133 if constexpr( not is_root ) {
134 out_it.del_indent( );
136 out_it.next_member( );
137 if constexpr( not is_root ) {
143 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
144 constexpr WritableType
145 to_json_schema( ParseTag<JsonParseTypes::StringEscaped>,
146 WritableType out_it ) {
148 if constexpr( not is_root ) {
150 out_it.add_indent( );
151 out_it.next_member( );
153 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
154 if constexpr( not is_root ) {
155 out_it.del_indent( );
157 out_it.next_member( );
158 if constexpr( not is_root ) {
164 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
165 constexpr WritableType
166 to_json_schema( ParseTag<JsonParseTypes::StringRaw>,
167 WritableType out_it ) {
169 if constexpr( not is_root ) {
171 out_it.add_indent( );
172 out_it.next_member( );
174 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
175 if constexpr( not is_root ) {
176 out_it.del_indent( );
178 out_it.next_member( );
179 if constexpr( not is_root ) {
185 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
186 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Unsigned>,
187 WritableType out_it ) {
188 if constexpr( not is_root ) {
190 out_it.add_indent( );
191 out_it.next_member( );
193 out_it = utils::output_kv( out_it, R
"("type")", R"("integer")" );
195 out_it.next_member( );
196 out_it = utils::output_kv( out_it, R
"("minimum")", "0" );
197 if constexpr( not is_root ) {
198 out_it.del_indent( );
200 out_it.next_member( );
201 if constexpr( not is_root ) {
216 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
217 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
218 WritableType out_it );
229 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
230 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
231 WritableType out_it );
233 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
234 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
235 WritableType out_it );
237 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
238 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
239 WritableType out_it );
241 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
242 constexpr WritableType
243 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
244 WritableType out_it );
246 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
247 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
248 WritableType out_it );
250 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
251 constexpr WritableType
252 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
253 WritableType out_it );
255 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
256 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
257 WritableType out_it );
259 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
260 constexpr WritableType
261 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
262 WritableType out_it );
264 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
265 constexpr WritableType
266 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
267 WritableType out_it );
269 template<
typename,
typename>
270 struct json_class_processor;
276 template<
typename WritableType,
typename... JsonMembers>
277 struct json_class_processor<WritableType,
278 json_member_list<JsonMembers...>> {
280 static constexpr std::size_t size =
sizeof...( JsonMembers );
286 static constexpr WritableType process( WritableType out_it ) {
287 out_it = utils::output_kv( out_it, R
"("type")", R"("object")" );
289 out_it.next_member( );
290 out_it = utils::output_kv( out_it, R
"("properties")", "{" );
291 if constexpr(
sizeof...( JsonMembers ) > 0 ) {
292 out_it.add_indent( );
293 out_it.next_member( );
294 out_it = output_member_types(
295 out_it, std::index_sequence_for<JsonMembers...>{ } );
296 out_it.del_indent( );
297 out_it.next_member( );
301 out_it.next_member( );
302 out_it = utils::output_kv( out_it, R
"("required")", "[" );
303 if constexpr( not is_empty_pack_v<JsonMembers...> ) {
304 out_it.add_indent( );
305 out_it = output_required_members( out_it );
306 out_it.del_indent( );
307 out_it.next_member( );
310 if constexpr( ( has_dependent_member_v<JsonMembers> or ... ) ) {
312 out_it.next_member( );
313 out_it = utils::output_kv( out_it, R
"("dependencies")", "{" );
314 out_it.add_indent( );
315 bool is_first =
true;
316 out_it =
static_cast<WritableType
>(
318 json_link_no_name<json_link_no_name<JsonMembers>>>(
321 out_it.del_indent( );
324 out_it.next_member( );
332 static constexpr
auto indexer =
333 std::index_sequence_for<JsonMembers...>{ };
341 template<
typename JsonMember, std::
size_t Idx>
342 static constexpr WritableType output_member_type( WritableType &out_it,
350 out_it.write(
"\"", JsonMember::name,
"\":", out_it.space );
351 out_it = to_json_schema<JsonMember>(
352 ParseTag<JsonMember::expected_type>{ }, out_it );
353 if constexpr( Idx + 1 <
sizeof...( JsonMembers ) ) {
355 out_it.next_member( );
360 template<std::size_t... Is>
361 DAW_ATTRIB_INLINE
static constexpr WritableType
362 output_member_types( WritableType &out_it,
363 std::index_sequence<Is...> ) {
364 bool seen[
sizeof...( JsonMembers )]{ };
365 return static_cast<WritableType
>(
366 ( output_member_type<JsonMembers, Is>( out_it, seen ), ... ) );
369 template<
typename JsonMember>
370 static constexpr WritableType
371 output_required_member( WritableType &out_it,
bool &is_first ) {
372 if constexpr( not is_json_nullable_v<JsonMember> ) {
378 out_it.next_member( );
386 template<
typename JsonMember>
387 static constexpr WritableType output_dependency( WritableType &out_it,
389 if constexpr( has_dependent_member_v<JsonMember> ) {
395 out_it.next_member( );
396 out_it.write(
"\"", JsonMember::name,
"\":", out_it.space,
"[" );
397 out_it.add_indent( );
398 out_it.next_member( );
399 out_it.write(
"\"", dependent_member_t<JsonMember>::name,
"\"" );
400 out_it.del_indent( );
401 out_it.next_member( );
407 static constexpr WritableType
408 output_required_members( WritableType &out_it ) {
409 bool is_first =
true;
410 return ( output_required_member<json_link_no_name<JsonMembers>>(
416 template<
typename WritableType,
typename... JsonMembers>
417 struct json_class_processor<WritableType,
418 json_tuple_member_list<JsonMembers...>> {
420 static constexpr std::size_t size =
sizeof...( JsonMembers );
421 static constexpr WritableType process( WritableType out_it ) {
423 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
424 out_it.next_member( );
425 out_it = utils::output_kv( out_it, R"("items")", "[" );
426 if constexpr(
sizeof...( JsonMembers ) > 0 ) {
427 out_it.add_indent( );
428 out_it = output_member_types( out_it );
429 out_it.del_indent( );
430 out_it.next_member( );
435 not( ( json_link_no_name<JsonMembers>::expected_type ==
436 JsonParseTypes::VariantTagged ) or
438 "A tagged variant is not supported in a tuple/ordered json "
443 static constexpr WritableType
444 output_member_types( WritableType &out_it ) {
445 bool is_first =
true;
446 return static_cast<WritableType
>(
447 ( output_member_type<json_link_no_name<JsonMembers>>( out_it,
452 template<
typename JsonMember>
453 static constexpr WritableType output_member_type( WritableType &out_it,
460 out_it.next_member( );
461 out_it = to_json_schema<JsonMember>(
462 ParseTag<JsonMember::expected_type>{ }, out_it );
467 template<
typename JsonMember,
bool is_root,
typename WritableType>
468 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
469 WritableType out_it ) {
470 using json_class_processor_t = json_class_processor<
472 json_data_contract_trait_t<json_base_type_t<JsonMember>>>;
474 if constexpr( not is_root ) {
476 out_it.add_indent( );
478 if constexpr( json_class_processor_t::size > 0 ) {
479 out_it.next_member( );
480 out_it = json_class_processor_t::process( out_it );
482 if constexpr( not is_root ) {
483 out_it.del_indent( );
485 if constexpr( not is_root ) {
486 out_it.next_member( );
492 namespace json_details {
493 template<
typename Tuple,
bool is_root,
typename WritableType,
495 DAW_ATTRIB_INLINE constexpr WritableType
496 to_json_tuple_schema( WritableType out_it,
497 std::index_sequence<Is...> ) {
498 if constexpr( not is_root ) {
500 out_it.add_indent( );
502 out_it.next_member( );
503 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
504 out_it.next_member( );
505 out_it = utils::output_kv( out_it, R"("items")", "[" );
506 if constexpr(
sizeof...( Is ) > 0 ) {
507 out_it.add_indent( );
508 bool is_first =
true;
509 auto const process_member = [&is_first, &out_it](
auto Idx ) {
515 out_it.next_member( );
516 constexpr std::size_t index = Idx.value;
517 using pack_element = tuple_elements_pack<Tuple>;
518 using JsonMember = json_deduced_type<
519 typename pack_element::template element_t<index>>;
521 out_it = to_json_schema<JsonMember>(
522 ParseTag<JsonMember::expected_type>{ }, out_it );
525 daw::empty_t expander[] = {
526 ( process_member( daw::constant_v<Is> ), daw::empty_t{ } )...,
529 out_it.del_indent( );
530 out_it.next_member( );
533 if constexpr( not is_root ) {
534 out_it.del_indent( );
536 out_it.next_member( );
537 if constexpr( not is_root ) {
544 template<
typename JsonMember,
bool is_root,
typename WritableType>
545 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
546 WritableType out_it ) {
547 using tuple_t =
typename JsonMember::sub_member_list;
548 return json_details::to_json_tuple_schema<tuple_t, is_root>(
550 std::make_index_sequence<tuple_elements_pack<tuple_t>::size>{ } );
553 template<
typename JsonMember,
bool is_root,
typename WritableType>
554 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
555 WritableType out_it ) {
556 if constexpr( not is_root ) {
558 out_it.add_indent( );
560 out_it.next_member( );
561 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
562 out_it.next_member( );
563 out_it.write( "\"items\":", out_it.space );
564 using element_t =
typename JsonMember::json_element_t;
565 out_it = to_json_schema<element_t>(
566 ParseTag<element_t::expected_type>{ }, out_it );
567 if constexpr( not is_root ) {
568 out_it.del_indent( );
570 out_it.next_member( );
571 if constexpr( not is_root ) {
577 template<
typename JsonMember,
bool is_root,
typename WritableType>
578 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
579 WritableType out_it ) {
580 using sub_member =
typename JsonMember::member_type;
581 return to_json_schema<sub_member, is_root>(
582 ParseTag<sub_member::expected_type>{ }, out_it );
585 template<
typename JsonMember,
bool is_root,
typename WritableType>
586 constexpr WritableType
587 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
588 WritableType out_it ) {
589 return to_json_schema<JsonMember, is_root>(
590 ParseTag<JsonParseTypes::Array>{ }, out_it );
593 template<
typename JsonMember,
bool is_root,
typename WritableType>
594 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
595 WritableType out_it ) {
596 if constexpr( not is_root ) {
598 out_it.add_indent( );
600 out_it.next_member( );
601 out_it = utils::output_kv( out_it, R
"("type")", R"("object")" );
603 out_it.next_member( );
604 out_it = utils::output_kv( out_it, R
"("additionalProperties")", "" );
605 using element_t =
typename JsonMember::json_element_t;
606 out_it = to_json_schema<element_t>(
607 ParseTag<element_t::expected_type>{ }, out_it );
608 if constexpr( not is_root ) {
609 out_it.del_indent( );
611 out_it.next_member( );
612 if constexpr( not is_root ) {
618 template<
typename JsonMember,
bool is_root,
typename WritableType>
619 constexpr WritableType
620 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
621 WritableType out_it ) {
622 if constexpr( not is_root ) {
624 out_it.add_indent( );
626 out_it.next_member( );
627 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
628 out_it.next_member( );
629 out_it.write( "\"items\":", out_it.space );
630 using element_t =
typename JsonMember::json_class_t;
631 out_it = to_json_schema<element_t>(
632 ParseTag<element_t::expected_type>{ }, out_it );
633 if constexpr( not is_root ) {
634 out_it.del_indent( );
636 out_it.next_member( );
637 if constexpr( not is_root ) {
643 template<
typename...>
644 struct variant_element_types;
646 template<
typename... JsonElements>
647 struct variant_element_types<json_variant_type_list<JsonElements...>> {
649 template<
typename JsonElement,
typename WritableType>
650 static constexpr WritableType output_element( WritableType out_it,
657 out_it.next_member( );
658 return to_json_schema<JsonElement>(
659 ParseTag<JsonElement::expected_type>{ }, out_it );
662 template<
typename WritableType>
663 static constexpr WritableType output_elements( WritableType out_it ) {
664 bool is_first =
true;
665 return static_cast<WritableType
>(
666 ( output_element<JsonElements>( out_it, is_first ), ... ) );
670 template<
typename JsonMember,
bool is_root,
typename WritableType>
671 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
672 WritableType out_it ) {
673 if constexpr( not is_root ) {
675 out_it.add_indent( );
677 out_it.next_member( );
678 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
679 using elements_t =
typename JsonMember::json_elements;
680 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
681 out_it.add_indent( );
682 out_it = variant_element_types<elements_t>::output_elements( out_it );
683 out_it.del_indent( );
684 out_it.next_member( );
687 if constexpr( not is_root ) {
688 out_it.del_indent( );
690 out_it.next_member( );
691 if constexpr( not is_root ) {
697 template<
typename JsonMember,
bool is_root,
typename WritableType>
698 constexpr WritableType
699 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
700 WritableType out_it ) {
701 static_assert( not is_root,
702 "Attempt to have a tagged variant as root object. This "
705 out_it.add_indent( );
706 out_it.next_member( );
707 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
708 using elements_t =
typename JsonMember::json_elements;
709 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
710 out_it.add_indent( );
711 out_it = variant_element_types<elements_t>::output_elements( out_it );
712 out_it.del_indent( );
713 out_it.next_member( );
716 out_it.del_indent( );
717 out_it.next_member( );
722 template<
typename JsonMember,
bool is_root,
typename WritableType>
723 constexpr WritableType
724 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
725 WritableType out_it ) {
726 if constexpr( not is_root ) {
728 out_it.add_indent( );
730 out_it.next_member( );
731 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
732 using elements_t =
typename JsonMember::json_elements;
733 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
734 out_it.add_indent( );
735 out_it = variant_element_types<elements_t>::output_elements( out_it );
736 out_it.del_indent( );
737 out_it.next_member( );
740 if constexpr( not is_root ) {
741 out_it.del_indent( );
743 out_it.next_member( );
744 if constexpr( not is_root ) {
759 template<
typename T,
typename WritableType,
auto... PolicyFlags>
760 constexpr WritableType to_json_schema(
761 WritableType &it, std::string_view
id, std::string_view title,
762 options::output_flags_t<PolicyFlags...> = options::output_flags<> ) {
764 auto out_it = [&it] {
765 if constexpr( is_serialization_policy_v<WritableType> ) {
766 if constexpr(
sizeof...( PolicyFlags ) == 0 ) {
769 return serialization_policy<
typename WritableType::iterator_type,
770 json_details::serialization::set_bits(
771 WritableType::policy_flags( ),
772 PolicyFlags... )>( it.get( ) );
775 return serialization_policy<
776 WritableType, options::output_flags_t<PolicyFlags...>::value>( it );
780 out_it.add_indent( );
781 out_it.next_member( );
782 out_it = utils::output_kv(
783 out_it, R
"("$schema")",
784 R"("https://json-schema.org/draft/2020-12/schema",)" );
785 out_it.next_member( );
786 out_it = utils::output_kv( out_it, R"("$id")", "\"" );
789 out_it.next_member( );
790 out_it = utils::output_kv( out_it, R"("title")", "\"" );
793 using json_type = json_link_no_name<T>;
794 out_it = json_details::to_json_schema<json_type, true>(
795 ParseTag<json_type::expected_type>{ }, out_it );
796 out_it.del_indent( );
797 out_it.next_member( );
799 return out_it.get( );
811 template<
typename T,
typename Result = std::string,
auto... PolicyFlags>
813 to_json_schema( std::string_view
id, std::string_view title,
814 options::output_flags_t<PolicyFlags...> flags =
815 options::output_flags<> ) {
816 auto result = Result( );
818 (void)to_json_schema<T>( result,
id, title, flags );
@ Tuple
A variant type where the Switcher is based on a submember of the class being parsed.
static constexpr WriteableType copy_to_iterator(WriteableType it, char const *ptr)
Customization point traits.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.