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 "impl/version.h"
12 
13 #include <daw/daw_utility.h>
14 
15 #include "daw_json_link_types.h"
16 #include "daw_to_json_fwd.h"
19 
20 namespace daw::json {
21  inline namespace DAW_JSON_VER {
22  namespace utils {
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 );
28  return it;
29  }
30  } // namespace utils
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 ) {
36 
37  if constexpr( not is_root ) {
38  out_it.put( '{' );
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.put( '}' );
49  }
50  return out_it;
51  }
52 
53  template<typename JsonMember, bool is_root = false,
54  typename WriteableType>
55  constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Custom>,
56  WriteableType 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 ==
60  options::JsonCustomTypes::String );
61  if constexpr( not is_root ) {
62  out_it.put( '{' );
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.put( '}' );
73  }
74  return out_it;
75  }
76 
77  template<typename JsonMember, bool is_root = false,
78  typename WriteableType>
79  constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Date>,
80  WriteableType out_it ) {
81 
82  if constexpr( not is_root ) {
83  out_it.put( '{' );
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.put( ',' );
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.put( '}' );
97  }
98  return out_it;
99  }
100 
101  template<typename JsonMember, bool is_root = false,
102  typename WriteableType>
103  constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Real>,
104  WriteableType out_it ) {
105 
106  if constexpr( not is_root ) {
107  out_it.put( '{' );
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.put( '}' );
118  }
119  return out_it;
120  }
121 
122  template<typename JsonMember, bool is_root = false,
123  typename WriteableType>
124  constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Signed>,
125  WriteableType out_it ) {
126 
127  if constexpr( not is_root ) {
128  out_it.put( '{' );
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.put( '}' );
139  }
140  return out_it;
141  }
142 
143  template<typename JsonMember, bool is_root = false, typename WritableType>
144  constexpr WritableType
145  to_json_schema( ParseTag<JsonParseTypes::StringEscaped>,
146  WritableType out_it ) {
147 
148  if constexpr( not is_root ) {
149  out_it.put( '{' );
150  out_it.add_indent( );
151  out_it.next_member( );
152  }
153  out_it = utils::output_kv( out_it, R"("type")", R"("string")" );
154  if constexpr( not is_root ) {
155  out_it.del_indent( );
156  }
157  out_it.next_member( );
158  if constexpr( not is_root ) {
159  out_it.put( '}' );
160  }
161  return out_it;
162  }
163 
164  template<typename JsonMember, bool is_root = false, typename WritableType>
165  constexpr WritableType
166  to_json_schema( ParseTag<JsonParseTypes::StringRaw>,
167  WritableType out_it ) {
168 
169  if constexpr( not is_root ) {
170  out_it.put( '{' );
171  out_it.add_indent( );
172  out_it.next_member( );
173  }
174  out_it = utils::output_kv( out_it, R"("type")", R"("string")" );
175  if constexpr( not is_root ) {
176  out_it.del_indent( );
177  }
178  out_it.next_member( );
179  if constexpr( not is_root ) {
180  out_it.put( '}' );
181  }
182  return out_it;
183  }
184 
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 ) {
189  out_it.put( '{' );
190  out_it.add_indent( );
191  out_it.next_member( );
192  }
193  out_it = utils::output_kv( out_it, R"("type")", R"("integer")" );
194  out_it.put( ',' );
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( );
199  }
200  out_it.next_member( );
201  if constexpr( not is_root ) {
202  out_it.put( '}' );
203  }
204  return out_it;
205  }
206 
207  /***
208  * Output the schema of a json_class and it's members
209  * @tparam JsonMember A json_class type
210  * @tparam is_root Is this the root item in the schema.
211  * @tparam WritableType An iterator type that allows for assigning to
212  * the result of operator* and pre/post-fix incrementing
213  * @param out_it Current WritableType
214  * @return the last value of out_it
215  */
216  template<typename JsonMember, bool is_root = false, typename WritableType>
217  constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
218  WritableType out_it );
219 
220  /***
221  * Output the schema of a json_array and it's element type
222  * @tparam JsonMember A json_array type
223  * @tparam is_root Is this the root item in the schema.
224  * @tparam WritableType An iterator type that allows for assigning to
225  * the result of operator and pre/post-fix incrementing
226  * @param out_it Current WritableType
227  * @return the last value of out_it
228  */
229  template<typename JsonMember, bool is_root = false, typename WritableType>
230  constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
231  WritableType out_it );
232 
233  template<typename JsonMember, bool is_root = false, typename WritableType>
234  constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
235  WritableType out_it );
236 
237  template<typename JsonMember, bool is_root = false, typename WritableType>
238  constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
239  WritableType out_it );
240 
241  template<typename JsonMember, bool is_root = false, typename WritableType>
242  constexpr WritableType
243  to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
244  WritableType out_it );
245 
246  template<typename JsonMember, bool is_root = false, typename WritableType>
247  constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
248  WritableType out_it );
249 
250  template<typename JsonMember, bool is_root = false, typename WritableType>
251  constexpr WritableType
252  to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
253  WritableType out_it );
254 
255  template<typename JsonMember, bool is_root = false, typename WritableType>
256  constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
257  WritableType out_it );
258 
259  template<typename JsonMember, bool is_root = false, typename WritableType>
260  constexpr WritableType
261  to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
262  WritableType out_it );
263 
264  template<typename JsonMember, bool is_root = false, typename WritableType>
265  constexpr WritableType
266  to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
267  WritableType out_it );
268 
269  template<typename, typename>
270  struct json_class_processor;
271 
276  template<typename WritableType, typename... JsonMembers>
277  struct json_class_processor<WritableType,
278  json_member_list<JsonMembers...>> {
279 
280  static constexpr std::size_t size = sizeof...( JsonMembers );
281 
286  static constexpr WritableType process( WritableType out_it ) {
287  out_it = utils::output_kv( out_it, R"("type")", R"("object")" );
288  out_it.put( ',' );
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( );
298  }
299  out_it.put( '}' );
300  out_it.put( ',' );
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( );
308  }
309  out_it.put( ']' );
310  if constexpr( ( has_dependent_member_v<JsonMembers> or ... ) ) {
311  out_it.put( ',' );
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>(
317  ( output_dependency<
318  json_link_no_name<json_link_no_name<JsonMembers>>>(
319  out_it, is_first ),
320  ... ) );
321  out_it.del_indent( );
322  if( not is_first ) {
323  // If we have at least 1 dependent member, is_first will be false
324  out_it.next_member( );
325  }
326  out_it.put( '}' );
327  }
328  return out_it;
329  }
330 
331  private:
332  static constexpr auto indexer =
333  std::index_sequence_for<JsonMembers...>{ };
334 
341  template<typename JsonMember, std::size_t Idx>
342  static constexpr WritableType output_member_type( WritableType &out_it,
343  bool *seen ) {
344  if( seen[Idx] ) {
345  return out_it;
346  } else {
347  seen[Idx] = true;
348  }
349 
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 ) ) {
354  out_it.put( ',' );
355  out_it.next_member( );
356  }
357  return out_it;
358  }
359 
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 ), ... ) );
367  }
368 
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> ) {
373  if( not is_first ) {
374  out_it.put( ',' );
375  } else {
376  is_first = false;
377  }
378  out_it.next_member( );
379  out_it.put( '"' );
380  out_it = utils::copy_to_iterator( out_it, JsonMember::name );
381  out_it.put( '"' );
382  }
383  return out_it;
384  }
385 
386  template<typename JsonMember>
387  static constexpr WritableType output_dependency( WritableType &out_it,
388  bool &is_first ) {
389  if constexpr( has_dependent_member_v<JsonMember> ) {
390  if( not is_first ) {
391  out_it.put( ',' );
392  } else {
393  is_first = false;
394  }
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( );
402  out_it.put( ']' );
403  }
404  return out_it;
405  }
406 
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>>(
411  out_it, is_first ),
412  ... );
413  }
414  };
415 
416  template<typename WritableType, typename... JsonMembers>
417  struct json_class_processor<WritableType,
418  json_tuple_member_list<JsonMembers...>> {
419 
420  static constexpr std::size_t size = sizeof...( JsonMembers );
421  static constexpr WritableType process( WritableType out_it ) {
422 
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( );
431  }
432  out_it.put( ']' );
433 
434  static_assert(
435  not( ( json_link_no_name<JsonMembers>::expected_type ==
436  JsonParseTypes::VariantTagged ) or
437  ... ),
438  "A tagged variant is not supported in a tuple/ordered json "
439  "class" );
440  return out_it;
441  }
442 
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,
448  is_first ),
449  ... ) );
450  }
451 
452  template<typename JsonMember>
453  static constexpr WritableType output_member_type( WritableType &out_it,
454  bool &is_first ) {
455  if( not is_first ) {
456  out_it.put( ',' );
457  } else {
458  is_first = false;
459  }
460  out_it.next_member( );
461  out_it = to_json_schema<JsonMember>(
462  ParseTag<JsonMember::expected_type>{ }, out_it );
463  return out_it;
464  }
465  };
466 
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<
471  WritableType,
472  json_data_contract_trait_t<json_base_type_t<JsonMember>>>;
473 
474  if constexpr( not is_root ) {
475  out_it.put( '{' );
476  out_it.add_indent( );
477  }
478  if constexpr( json_class_processor_t::size > 0 ) {
479  out_it.next_member( );
480  out_it = json_class_processor_t::process( out_it );
481  }
482  if constexpr( not is_root ) {
483  out_it.del_indent( );
484  }
485  if constexpr( not is_root ) {
486  out_it.next_member( );
487  out_it.put( '}' );
488  }
489  return out_it;
490  }
491 
492  namespace json_details {
493  template<typename Tuple, bool is_root, typename WritableType,
494  std::size_t... Is>
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 ) {
499  out_it.put( '{' );
500  out_it.add_indent( );
501  }
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 ) {
510  if( not is_first ) {
511  out_it.put( ',' );
512  } else {
513  is_first = false;
514  }
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>>;
520 
521  out_it = to_json_schema<JsonMember>(
522  ParseTag<JsonMember::expected_type>{ }, out_it );
523  };
524 
525  daw::empty_t expander[] = {
526  ( process_member( daw::constant_v<Is> ), daw::empty_t{ } )...,
527  daw::empty_t{} };
528  (void)expander;
529  out_it.del_indent( );
530  out_it.next_member( );
531  }
532  out_it.put( ']' );
533  if constexpr( not is_root ) {
534  out_it.del_indent( );
535  }
536  out_it.next_member( );
537  if constexpr( not is_root ) {
538  out_it.put( '}' );
539  }
540  return out_it;
541  }
542  } // namespace json_details
543 
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>(
549  out_it,
550  std::make_index_sequence<tuple_elements_pack<tuple_t>::size>{ } );
551  }
552 
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 ) {
557  out_it.put( '{' );
558  out_it.add_indent( );
559  }
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( );
569  }
570  out_it.next_member( );
571  if constexpr( not is_root ) {
572  out_it.put( '}' );
573  }
574  return out_it;
575  }
576 
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 );
583  }
584 
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 );
591  }
592 
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 ) {
597  out_it.put( '{' );
598  out_it.add_indent( );
599  }
600  out_it.next_member( );
601  out_it = utils::output_kv( out_it, R"("type")", R"("object")" );
602  out_it.put( ',' );
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( );
610  }
611  out_it.next_member( );
612  if constexpr( not is_root ) {
613  out_it.put( '}' );
614  }
615  return out_it;
616  }
617 
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 ) {
623  out_it.put( '{' );
624  out_it.add_indent( );
625  }
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( );
635  }
636  out_it.next_member( );
637  if constexpr( not is_root ) {
638  out_it.put( '}' );
639  }
640  return out_it;
641  }
642 
643  template<typename...>
644  struct variant_element_types;
645 
646  template<typename... JsonElements>
647  struct variant_element_types<json_variant_type_list<JsonElements...>> {
648 
649  template<typename JsonElement, typename WritableType>
650  static constexpr WritableType output_element( WritableType out_it,
651  bool &is_first ) {
652  if( not is_first ) {
653  out_it.put( ',' );
654  } else {
655  is_first = false;
656  }
657  out_it.next_member( );
658  return to_json_schema<JsonElement>(
659  ParseTag<JsonElement::expected_type>{ }, out_it );
660  }
661 
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 ), ... ) );
667  }
668  };
669 
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 ) {
674  out_it.put( '{' );
675  out_it.add_indent( );
676  }
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( );
685  }
686  out_it.put( ']' );
687  if constexpr( not is_root ) {
688  out_it.del_indent( );
689  }
690  out_it.next_member( );
691  if constexpr( not is_root ) {
692  out_it.put( '}' );
693  }
694  return out_it;
695  }
696 
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 "
703  "is unsupported" );
704  out_it.put( '{' );
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( );
714  }
715  out_it.put( ']' );
716  out_it.del_indent( );
717  out_it.next_member( );
718  out_it.put( '}' );
719  return out_it;
720  }
721 
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 ) {
727  out_it.put( '{' );
728  out_it.add_indent( );
729  }
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( );
738  }
739  out_it.put( ']' );
740  if constexpr( not is_root ) {
741  out_it.del_indent( );
742  }
743  out_it.next_member( );
744  if constexpr( not is_root ) {
745  out_it.put( '}' );
746  }
747  return out_it;
748  }
749  } // namespace json_details
750 
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<> ) {
763 
764  auto out_it = [&it] {
765  if constexpr( is_serialization_policy_v<WritableType> ) {
766  if constexpr( sizeof...( PolicyFlags ) == 0 ) {
767  return it;
768  } else {
769  return serialization_policy<typename WritableType::iterator_type,
770  json_details::serialization::set_bits(
771  WritableType::policy_flags( ),
772  PolicyFlags... )>( it.get( ) );
773  }
774  } else {
775  return serialization_policy<
776  WritableType, options::output_flags_t<PolicyFlags...>::value>( it );
777  }
778  }( );
779  out_it.put( '{' );
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::expected_type>{ }, out_it );
796  out_it.del_indent( );
797  out_it.next_member( );
798  out_it.put( '}' );
799  return out_it.get( );
800  }
801 
811  template<typename T, typename Result = std::string, auto... PolicyFlags>
812  constexpr Result
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( );
817 
818  (void)to_json_schema<T>( result, id, title, flags );
819  return result;
820  }
821  } // namespace DAW_JSON_VER
822 } // namespace daw::json
@ 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.
Definition: version.h:25