DAW JSON Link
daw_json_schema.h
Go to the documentation of this file.
1// Copyright (c) Darrell Wright
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5//
6// Official repository: https://github.com/beached/daw_json_link
7//
8
9#pragma once
10
11#include <daw/daw_utility.h>
12
13#include "daw_json_link_types.h"
16
17namespace daw::json {
18 inline namespace DAW_JSON_VER {
19 namespace utils {
20 template<typename OutputIterator>
21 inline constexpr OutputIterator output_kv( OutputIterator it,
22 std::string_view key,
23 std::string_view value ) {
24 it = copy_to_iterator( it, key );
25 *it++ = ':';
26 it.output_space( );
27 it = copy_to_iterator( it, value );
28 return it;
29 }
30 } // namespace utils
31 namespace json_details {
32 template<typename JsonMember, bool is_root = false,
33 typename OutputIterator>
34 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Bool>,
35 OutputIterator out_it ) {
36
37 if constexpr( not is_root ) {
38 *out_it++ = '{';
39 out_it.add_indent( );
40 out_it.next_member( );
41 }
42 out_it = utils::output_kv( out_it, R"("type")", R"("boolean")" );
43 if constexpr( not is_root ) {
44 out_it.del_indent( );
45 }
46 out_it.next_member( );
47 if constexpr( not is_root ) {
48 *out_it++ = '}';
49 }
50 return out_it;
51 }
52
53 template<typename JsonMember, bool is_root = false,
54 typename OutputIterator>
55 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Custom>,
56 OutputIterator out_it ) {
57 // TODO allow a trait to describe the valid literal types or if it
58 // matches one of the other predefined types
59 static_assert( JsonMember::custom_json_type ==
61 if constexpr( not is_root ) {
62 *out_it++ = '{';
63 out_it.add_indent( );
64 out_it.next_member( );
65 }
66 out_it = utils::output_kv( out_it, R"("type")", R"("string")" );
67 if constexpr( not is_root ) {
68 out_it.del_indent( );
69 }
70 out_it.next_member( );
71 if constexpr( not is_root ) {
72 *out_it++ = '}';
73 }
74 return out_it;
75 }
76
77 template<typename JsonMember, bool is_root = false,
78 typename OutputIterator>
79 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Date>,
80 OutputIterator out_it ) {
81
82 if constexpr( not is_root ) {
83 *out_it++ = '{';
84 out_it.add_indent( );
85 out_it.next_member( );
86 }
87 out_it = utils::output_kv( out_it, R"("type")", R"("string")" );
88 *out_it++ = ',';
89 out_it.next_member( );
90 out_it = utils::output_kv( out_it, R"("format")", R"("date-time")" );
91 if constexpr( not is_root ) {
92 out_it.del_indent( );
93 }
94 out_it.next_member( );
95 if constexpr( not is_root ) {
96 *out_it++ = '}';
97 }
98 return out_it;
99 }
100
101 template<typename JsonMember, bool is_root = false,
102 typename OutputIterator>
103 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Real>,
104 OutputIterator out_it ) {
105
106 if constexpr( not is_root ) {
107 *out_it++ = '{';
108 out_it.add_indent( );
109 out_it.next_member( );
110 }
111 out_it = utils::output_kv( out_it, R"("type")", R"("number")" );
112 if constexpr( not is_root ) {
113 out_it.del_indent( );
114 }
115 out_it.next_member( );
116 if constexpr( not is_root ) {
117 *out_it++ = '}';
118 }
119 return out_it;
120 }
121
122 template<typename JsonMember, bool is_root = false,
123 typename OutputIterator>
124 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Signed>,
125 OutputIterator out_it ) {
126
127 if constexpr( not is_root ) {
128 *out_it++ = '{';
129 out_it.add_indent( );
130 out_it.next_member( );
131 }
132 out_it = utils::output_kv( out_it, R"("type")", R"("integer")" );
133 if constexpr( not is_root ) {
134 out_it.del_indent( );
135 }
136 out_it.next_member( );
137 if constexpr( not is_root ) {
138 *out_it++ = '}';
139 }
140 return out_it;
141 }
142
143 template<typename JsonMember, bool is_root = false,
144 typename OutputIterator>
145 constexpr OutputIterator
146 to_json_schema( ParseTag<JsonParseTypes::StringEscaped>,
147 OutputIterator out_it ) {
148
149 if constexpr( not is_root ) {
150 *out_it++ = '{';
151 out_it.add_indent( );
152 out_it.next_member( );
153 }
154 out_it = utils::output_kv( out_it, R"("type")", R"("string")" );
155 if constexpr( not is_root ) {
156 out_it.del_indent( );
157 }
158 out_it.next_member( );
159 if constexpr( not is_root ) {
160 *out_it++ = '}';
161 }
162 return out_it;
163 }
164
165 template<typename JsonMember, bool is_root = false,
166 typename OutputIterator>
167 constexpr OutputIterator
168 to_json_schema( ParseTag<JsonParseTypes::StringRaw>,
169 OutputIterator out_it ) {
170
171 if constexpr( not is_root ) {
172 *out_it++ = '{';
173 out_it.add_indent( );
174 out_it.next_member( );
175 }
176 out_it = utils::output_kv( out_it, R"("type")", R"("string")" );
177 if constexpr( not is_root ) {
178 out_it.del_indent( );
179 }
180 out_it.next_member( );
181 if constexpr( not is_root ) {
182 *out_it++ = '}';
183 }
184 return out_it;
185 }
186
187 template<typename JsonMember, bool is_root = false,
188 typename OutputIterator>
189 constexpr OutputIterator
190 to_json_schema( ParseTag<JsonParseTypes::Unsigned>,
191 OutputIterator out_it ) {
192 if constexpr( not is_root ) {
193 *out_it++ = '{';
194 out_it.add_indent( );
195 out_it.next_member( );
196 }
197 out_it = utils::output_kv( out_it, R"("type")", R"("integer")" );
198 *out_it++ = ',';
199 out_it.next_member( );
200 out_it = utils::output_kv( out_it, R"("minimum")", "0" );
201 if constexpr( not is_root ) {
202 out_it.del_indent( );
203 }
204 out_it.next_member( );
205 if constexpr( not is_root ) {
206 *out_it++ = '}';
207 }
208 return out_it;
209 }
210
211 /***
212 * Output the schema of a json_class and it's members
213 * @tparam JsonMember A json_class type
214 * @tparam is_root Is this the root item in the schema.
215 * @tparam OutputIterator An iterator type that allows for assigning to
216 * the result of operator* and pre/post-fix incrementing
217 * @param out_it Current OutputIterator
218 * @return the last value of out_it
219 */
220 template<typename JsonMember, bool is_root = false,
221 typename OutputIterator>
222 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Class>,
223 OutputIterator out_it );
224
225 /***
226 * Output the schema of a json_array and it's element type
227 * @tparam JsonMember A json_array type
228 * @tparam is_root Is this the root item in the schema.
229 * @tparam OutputIterator An iterator type that allows for assigning to
230 * the result of operator and pre/post-fix incrementing
231 * @param out_it Current OutputIterator
232 * @return the last value of out_it
233 */
234 template<typename JsonMember, bool is_root = false,
235 typename OutputIterator>
236 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Array>,
237 OutputIterator out_it );
238
239 template<typename JsonMember, bool is_root = false,
240 typename OutputIterator>
241 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Tuple>,
242 OutputIterator out_it );
243
244 template<typename JsonMember, bool is_root = false,
245 typename OutputIterator>
246 constexpr OutputIterator
247 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
248 OutputIterator out_it );
249
250 template<typename JsonMember, bool is_root = false,
251 typename OutputIterator>
252 constexpr OutputIterator
253 to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
254 OutputIterator out_it );
255
256 template<typename JsonMember, bool is_root = false,
257 typename OutputIterator>
258 constexpr OutputIterator
259 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
260 OutputIterator out_it );
261
262 template<typename JsonMember, bool is_root = false,
263 typename OutputIterator>
264 constexpr OutputIterator
265 to_json_schema( ParseTag<JsonParseTypes::Variant>,
266 OutputIterator out_it );
267
268 template<typename JsonMember, bool is_root = false,
269 typename OutputIterator>
270 constexpr OutputIterator
271 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
272 OutputIterator out_it );
273
274 template<typename JsonMember, bool is_root = false,
275 typename OutputIterator>
276 constexpr OutputIterator
277 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
278 OutputIterator out_it );
279
280 template<typename, typename>
281 struct json_class_processor;
282
287 template<typename OutputIterator, typename... JsonMembers>
288 struct json_class_processor<OutputIterator,
289 json_member_list<JsonMembers...>> {
290
291 static constexpr std::size_t size = sizeof...( JsonMembers );
292
297 static constexpr OutputIterator process( OutputIterator out_it ) {
298 out_it = utils::output_kv( out_it, R"("type")", R"("object")" );
299 *out_it++ = ',';
300 out_it.next_member( );
301 out_it = utils::output_kv( out_it, R"("properties")", "{" );
302 if constexpr( sizeof...( JsonMembers ) > 0 ) {
303 out_it.add_indent( );
304 out_it.next_member( );
305 out_it = output_member_types(
306 out_it, std::index_sequence_for<JsonMembers...>{ } );
307 out_it.del_indent( );
308 out_it.next_member( );
309 }
310 *out_it++ = '}';
311 *out_it++ = ',';
312 out_it.next_member( );
313 out_it = utils::output_kv( out_it, R"("required")", "[" );
314 if constexpr( not is_empty_pack_v<JsonMembers...> ) {
315 out_it.add_indent( );
316 out_it = output_required_members( out_it );
317 out_it.del_indent( );
318 out_it.next_member( );
319 }
320 *out_it++ = ']';
321 if constexpr( ( has_dependent_member_v<JsonMembers> or ... ) ) {
322 *out_it++ = ',';
323 out_it.next_member( );
324 out_it = utils::output_kv( out_it, R"("dependencies")", "{" );
325 out_it.add_indent( );
326 bool is_first = true;
327 out_it = static_cast<OutputIterator>(
328 ( output_dependency<
329 json_link_no_name<json_link_no_name<JsonMembers>>>(
330 out_it, is_first ),
331 ... ) );
332 out_it.del_indent( );
333 if( not is_first ) {
334 // If we have at least 1 dependent member, is_first will be false
335 out_it.next_member( );
336 }
337 *out_it++ = '}';
338 }
339 return out_it;
340 }
341
342 private:
343 static constexpr auto indexer =
344 std::index_sequence_for<JsonMembers...>{ };
345
352 template<typename JsonMember, std::size_t Idx>
353 static constexpr OutputIterator
354 output_member_type( OutputIterator &out_it, bool *seen ) {
355 if( seen[Idx] ) {
356 return out_it;
357 } else {
358 seen[Idx] = true;
359 }
360
361 *out_it++ = '"';
362 out_it = utils::copy_to_iterator( out_it, JsonMember::name );
363 out_it = utils::copy_to_iterator( out_it, R"(":)" );
364 out_it.output_space( );
365 out_it = to_json_schema<JsonMember>(
366 ParseTag<JsonMember::base_expected_type>{ }, out_it );
367 if constexpr( Idx + 1 < sizeof...( JsonMembers ) ) {
368 *out_it++ = ',';
369 out_it.next_member( );
370 }
371 return out_it;
372 }
373
374 template<std::size_t... Is>
375 static constexpr OutputIterator
376 output_member_types( OutputIterator &out_it,
377 std::index_sequence<Is...> ) {
378 bool seen[sizeof...( JsonMembers )]{ };
379 return static_cast<OutputIterator>(
380 ( output_member_type<JsonMembers, Is>( out_it, seen ), ... ) );
381 }
382
383 template<typename JsonMember>
384 static constexpr OutputIterator
385 output_required_member( OutputIterator &out_it, bool &is_first ) {
386 if constexpr( JsonMember::nullable == JsonNullable::MustExist ) {
387 if( not is_first ) {
388 *out_it++ = ',';
389 } else {
390 is_first = false;
391 }
392 out_it.next_member( );
393 *out_it++ = '"';
394 out_it = utils::copy_to_iterator( out_it, JsonMember::name );
395 *out_it++ = '"';
396 }
397 return out_it;
398 }
399
400 template<typename JsonMember>
401 static constexpr OutputIterator
402 output_dependency( OutputIterator &out_it, bool &is_first ) {
403 if constexpr( has_dependent_member_v<JsonMember> ) {
404 if( not is_first ) {
405 *out_it++ = ',';
406 } else {
407 is_first = false;
408 }
409 out_it.next_member( );
410 *out_it++ = '"';
411 out_it = utils::copy_to_iterator( out_it, JsonMember::name );
412 out_it = utils::copy_to_iterator( out_it, R"(":)" );
413 out_it.output_space( );
414 *out_it++ = '[';
415 out_it.add_indent( );
416 out_it.next_member( );
417 *out_it++ = '"';
419 out_it, dependent_member_t<JsonMember>::name );
420 *out_it++ = '"';
421 out_it.del_indent( );
422 out_it.next_member( );
423 *out_it++ = ']';
424 }
425 return out_it;
426 }
427
428 static constexpr OutputIterator
429 output_required_members( OutputIterator &out_it ) {
430 bool is_first = true;
431 return ( output_required_member<json_link_no_name<JsonMembers>>(
432 out_it, is_first ),
433 ... );
434 }
435 };
436
437 template<typename OutputIterator, typename... JsonMembers>
438 struct json_class_processor<OutputIterator,
439 json_tuple_member_list<JsonMembers...>> {
440
441 static constexpr std::size_t size = sizeof...( JsonMembers );
442 static constexpr OutputIterator process( OutputIterator out_it ) {
443
444 out_it = utils::output_kv( out_it, R"("type")", R"("array",)" );
445 out_it.next_member( );
446 out_it = utils::output_kv( out_it, R"("items")", "[" );
447 if constexpr( sizeof...( JsonMembers ) > 0 ) {
448 out_it.add_indent( );
449 out_it = output_member_types( out_it );
450 out_it.del_indent( );
451 out_it.next_member( );
452 }
453 *out_it++ = ']';
454
455 static_assert(
456 not( ( json_link_no_name<JsonMembers>::base_expected_type ==
458 ... ),
459 "A tagged variant is not supported in a tuple/ordered json "
460 "class" );
461 return out_it;
462 }
463
464 static constexpr OutputIterator
465 output_member_types( OutputIterator &out_it ) {
466 bool is_first = true;
467 return static_cast<OutputIterator>(
468 ( output_member_type<json_link_no_name<JsonMembers>>( out_it,
469 is_first ),
470 ... ) );
471 }
472
473 template<typename JsonMember>
474 static constexpr OutputIterator
475 output_member_type( OutputIterator &out_it, bool &is_first ) {
476 if( not is_first ) {
477 *out_it++ = ',';
478 } else {
479 is_first = false;
480 }
481 out_it.next_member( );
482 out_it = to_json_schema<JsonMember>(
483 ParseTag<JsonMember::base_expected_type>{ }, out_it );
484 return out_it;
485 }
486 };
487
488 template<typename JsonMember, bool is_root, typename OutputIterator>
489 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Class>,
490 OutputIterator out_it ) {
491 using json_class_processor_t = json_class_processor<
492 OutputIterator,
493 json_data_contract_trait_t<typename JsonMember::base_type>>;
494
495 if constexpr( not is_root ) {
496 *out_it++ = '{';
497 out_it.add_indent( );
498 }
499 if constexpr( json_class_processor_t::size > 0 ) {
500 out_it.next_member( );
501 out_it = json_class_processor_t::process( out_it );
502 }
503 if constexpr( not is_root ) {
504 out_it.del_indent( );
505 }
506 if constexpr( not is_root ) {
507 out_it.next_member( );
508 *out_it++ = '}';
509 }
510 return out_it;
511 }
512
513 namespace json_details {
514 template<typename Tuple, bool is_root, typename OutputIterator,
515 std::size_t... Is>
516 constexpr OutputIterator
517 to_json_tuple_schema( OutputIterator out_it,
518 std::index_sequence<Is...> ) {
519 if constexpr( not is_root ) {
520 *out_it++ = '{';
521 out_it.add_indent( );
522 }
523 out_it.next_member( );
524 out_it = utils::output_kv( out_it, R"("type")", R"("array",)" );
525 out_it.next_member( );
526 out_it = utils::output_kv( out_it, R"("items")", "[" );
527 if constexpr( sizeof...( Is ) > 0 ) {
528 out_it.add_indent( );
529 bool is_first = true;
530 auto const process_member = [&]( auto Idx ) {
531 if( not is_first ) {
532 *out_it++ = ',';
533 } else {
534 is_first = false;
535 }
536 out_it.next_member( );
537 static constexpr std::size_t index = decltype( Idx )::value;
538 using pack_element = tuple_elements_pack<Tuple>;
539 using JsonMember = json_deduced_type<
540 typename pack_element::template element_t<index>>;
541
542 out_it = to_json_schema<JsonMember>(
543 ParseTag<JsonMember::base_expected_type>{ }, out_it );
544 };
545
546 daw::Empty expander[] = {
547 ( process_member( daw::constant<Is>{ } ), daw::Empty{ } )...,
548 daw::Empty{} };
549 (void)expander;
550 out_it.del_indent( );
551 out_it.next_member( );
552 }
553 *out_it++ = ']';
554 if constexpr( not is_root ) {
555 out_it.del_indent( );
556 }
557 out_it.next_member( );
558 if constexpr( not is_root ) {
559 *out_it++ = '}';
560 }
561 return out_it;
562 }
563 } // namespace json_details
564
565 template<typename JsonMember, bool is_root, typename OutputIterator>
566 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Tuple>,
567 OutputIterator out_it ) {
568 using tuple_t = typename JsonMember::sub_member_list;
569 return json_details::to_json_tuple_schema<tuple_t, is_root>(
570 out_it,
571 std::make_index_sequence<tuple_elements_pack<tuple_t>::size>{ } );
572 }
573
574 template<typename JsonMember, bool is_root, typename OutputIterator>
575 constexpr OutputIterator to_json_schema( ParseTag<JsonParseTypes::Array>,
576 OutputIterator out_it ) {
577 if constexpr( not is_root ) {
578 *out_it++ = '{';
579 out_it.add_indent( );
580 }
581 out_it.next_member( );
582 out_it = utils::output_kv( out_it, R"("type")", R"("array",)" );
583 out_it.next_member( );
584 out_it = utils::copy_to_iterator( out_it, R"("items":)" );
585 out_it.output_space( );
586 using element_t = typename JsonMember::json_element_t;
587 out_it = to_json_schema<element_t>(
588 ParseTag<element_t::base_expected_type>{ }, out_it );
589 if constexpr( not is_root ) {
590 out_it.del_indent( );
591 }
592 out_it.next_member( );
593 if constexpr( not is_root ) {
594 *out_it++ = '}';
595 }
596 return out_it;
597 }
598
599 template<typename JsonMember, bool is_root, typename OutputIterator>
600 constexpr OutputIterator
601 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
602 OutputIterator out_it ) {
603 return to_json_schema<JsonMember, is_root>(
604 ParseTag<JsonParseTypes::Array>{ }, out_it );
605 }
606
607 template<typename JsonMember, bool is_root, typename OutputIterator>
608 constexpr OutputIterator
609 to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
610 OutputIterator out_it ) {
611 if constexpr( not is_root ) {
612 *out_it++ = '{';
613 out_it.add_indent( );
614 }
615 out_it.next_member( );
616 out_it = utils::output_kv( out_it, R"("type")", R"("object")" );
617 *out_it++ = ',';
618 out_it.next_member( );
619 out_it = utils::output_kv( out_it, R"("additionalProperties")", "" );
620 using element_t = typename JsonMember::json_element_t;
621 out_it = to_json_schema<element_t>(
622 ParseTag<element_t::base_expected_type>{ }, out_it );
623 if constexpr( not is_root ) {
624 out_it.del_indent( );
625 }
626 out_it.next_member( );
627 if constexpr( not is_root ) {
628 *out_it++ = '}';
629 }
630 return out_it;
631 }
632
633 template<typename JsonMember, bool is_root, typename OutputIterator>
634 constexpr OutputIterator
635 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
636 OutputIterator out_it ) {
637 if constexpr( not is_root ) {
638 *out_it++ = '{';
639 out_it.add_indent( );
640 }
641 out_it.next_member( );
642 out_it = utils::output_kv( out_it, R"("type")", R"("array",)" );
643 out_it.next_member( );
644 out_it = utils::copy_to_iterator( out_it, R"("items":)" );
645 out_it.output_space( );
646 using element_t = typename JsonMember::json_class_t;
647 out_it = to_json_schema<element_t>(
648 ParseTag<element_t::base_expected_type>{ }, out_it );
649 if constexpr( not is_root ) {
650 out_it.del_indent( );
651 }
652 out_it.next_member( );
653 if constexpr( not is_root ) {
654 *out_it++ = '}';
655 }
656 return out_it;
657 }
658
659 template<typename...>
660 struct variant_element_types;
661
662 template<typename... JsonElements>
663 struct variant_element_types<json_variant_type_list<JsonElements...>> {
664
665 template<typename JsonElement, typename OutputIterator>
666 static constexpr OutputIterator output_element( OutputIterator out_it,
667 bool &is_first ) {
668 if( not is_first ) {
669 *out_it++ = ',';
670 } else {
671 is_first = false;
672 }
673 out_it.next_member( );
674 return to_json_schema<JsonElement>(
675 ParseTag<JsonElement::base_expected_type>{ }, out_it );
676 }
677
678 template<typename OutputIterator>
679 static constexpr OutputIterator
680 output_elements( OutputIterator out_it ) {
681 bool is_first = true;
682 return static_cast<OutputIterator>(
683 ( output_element<JsonElements>( out_it, is_first ), ... ) );
684 }
685 };
686
687 template<typename JsonMember, bool is_root, typename OutputIterator>
688 constexpr OutputIterator
689 to_json_schema( ParseTag<JsonParseTypes::Variant>,
690 OutputIterator out_it ) {
691 if constexpr( not is_root ) {
692 *out_it++ = '{';
693 out_it.add_indent( );
694 }
695 out_it.next_member( );
696 out_it = utils::output_kv( out_it, R"("oneOf")", "[" );
697 using elements_t = typename JsonMember::json_elements;
698 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
699 out_it.add_indent( );
700 out_it = variant_element_types<elements_t>::output_elements( out_it );
701 out_it.del_indent( );
702 out_it.next_member( );
703 }
704 *out_it++ = ']';
705 if constexpr( not is_root ) {
706 out_it.del_indent( );
707 }
708 out_it.next_member( );
709 if constexpr( not is_root ) {
710 *out_it++ = '}';
711 }
712 return out_it;
713 }
714
715 template<typename JsonMember, bool is_root, typename OutputIterator>
716 constexpr OutputIterator
717 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
718 OutputIterator out_it ) {
719 static_assert( not is_root,
720 "Attempt to have a tagged variant as root object. This "
721 "is unsupported" );
722 *out_it++ = '{';
723 out_it.add_indent( );
724 out_it.next_member( );
725 out_it = utils::output_kv( out_it, R"("oneOf")", "[" );
726 using elements_t = typename JsonMember::json_elements;
727 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
728 out_it.add_indent( );
729 out_it = variant_element_types<elements_t>::output_elements( out_it );
730 out_it.del_indent( );
731 out_it.next_member( );
732 }
733 *out_it++ = ']';
734 out_it.del_indent( );
735 out_it.next_member( );
736 *out_it++ = '}';
737 return out_it;
738 }
739
740 template<typename JsonMember, bool is_root, typename OutputIterator>
741 constexpr OutputIterator
742 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
743 OutputIterator out_it ) {
744 if constexpr( not is_root ) {
745 *out_it++ = '{';
746 out_it.add_indent( );
747 }
748 out_it.next_member( );
749 out_it = utils::output_kv( out_it, R"("oneOf")", "[" );
750 using elements_t = typename JsonMember::json_elements;
751 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
752 out_it.add_indent( );
753 out_it = variant_element_types<elements_t>::output_elements( out_it );
754 out_it.del_indent( );
755 out_it.next_member( );
756 }
757 *out_it++ = ']';
758 if constexpr( not is_root ) {
759 out_it.del_indent( );
760 }
761 out_it.next_member( );
762 if constexpr( not is_root ) {
763 *out_it++ = '}';
764 }
765 return out_it;
766 }
767 } // namespace json_details
768
769 template<typename T, typename OutputIterator>
770 constexpr OutputIterator to_json_schema( OutputIterator it,
771 std::string_view id,
772 std::string_view title ) {
773
774 using iter_t =
775 std::conditional_t<is_serialization_policy<OutputIterator>::value,
776 OutputIterator,
777 serialization_policy<OutputIterator>>;
778 auto out_it = iter_t( it );
779 *out_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")", "\"" );
787 out_it = utils::copy_to_iterator( out_it, id );
788 out_it = utils::copy_to_iterator( out_it, R"(",)" );
789 out_it.next_member( );
790 out_it = utils::output_kv( out_it, R"("title")", "\"" );
791 out_it = utils::copy_to_iterator( out_it, title );
792 out_it = utils::copy_to_iterator( out_it, R"(",)" );
793 using json_type = json_link_no_name<T>;
794 out_it = json_details::to_json_schema<json_type, true>(
795 ParseTag<json_type::base_expected_type>{ }, out_it );
796 out_it.del_indent( );
797 out_it.next_member( );
798 *out_it++ = '}';
799 return out_it;
800 }
801
802 template<typename T,
803 typename SerializationPolicy = use_default_serialization_policy,
804 typename Result = std::string>
805 Result to_json_schema( std::string_view id, std::string_view title ) {
806 auto result = Result( );
807 using iter_t = std::back_insert_iterator<Result>;
808 using policy = std::conditional_t<
809 std::is_same_v<SerializationPolicy, use_default_serialization_policy>,
810 serialization_policy<iter_t>, SerializationPolicy>;
811
812 (void)to_json_schema<T>( policy( iter_t( result ) ), id, title );
813 return result;
814 }
815 } // namespace DAW_JSON_VER
816} // namespace daw::json
Iterator & it
Definition: daw_json_traits.h:251
typename json_type_deducer< T, is_an_ordered_member_v< T >, has_json_data_contract_trait_v< T >, json_details::is_a_json_type_v< T >, has_json_link_quick_map_v< T >, is_container_v< T > >::type json_deduced_type
Definition: daw_json_parse_common.h:953
constexpr OutputIterator copy_to_iterator(OutputIterator it, Container const &container)
Definition: to_daw_json_string.h:391
@ Tuple
A variant type where the Switcher is based on a submember of the class being parsed.
@ VariantTagged
Any one of the basic json types class/array/boolean/number/string.
constexpr bool is_empty_pack_v
Definition: daw_json_traits.h:191
Definition: daw_from_json.h:22
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16