DAW JSON Link
daw_from_json.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_from_json_fwd.h"
16 #include "impl/daw_json_value.h"
17 
18 #include <daw/daw_data_end.h>
19 #include <daw/traits/daw_traits_conditional.h>
20 
21 #include <daw/stdinc/data_access.h>
22 #include <daw/stdinc/move_fwd_exch.h>
23 #include <string_view>
24 
25 namespace daw::json {
26  inline namespace DAW_JSON_VER {
27 
36  template<typename JsonMember, bool KnownBounds, typename String,
37  auto... PolicyFlags>
38  [[nodiscard]] constexpr auto
39  from_json( String &&json_data, options::parse_flags_t<PolicyFlags...> ) {
40  static_assert(
41  json_details::is_string_view_like_v<String>,
42  "String type must have a be a contiguous range of Characters" );
43  daw_json_ensure( std::data( json_data ) != nullptr,
44  ErrorReason::EmptyJSONDocument );
45  daw_json_ensure( std::size( json_data ) != 0,
46  ErrorReason::EmptyJSONDocument );
47 
48  static_assert(
49  json_details::has_json_deduced_type_v<JsonMember>,
50  "Missing specialization of daw::json::json_data_contract for class "
51  "mapping or specialization of daw::json::json_link_basic_type_map" );
52  using json_member = json_details::json_deduced_type<JsonMember>;
53  using ParsePolicy =
54  BasicParsePolicy<options::parse_flags_t<PolicyFlags...>::value>;
55 
58  using policy_zstring_t = json_details::apply_zstring_policy_option_t<
59  ParsePolicy, String, options::ZeroTerminatedString::yes>;
60 
61  using ParseState =
62  daw::conditional_t<policy_zstring_t::is_default_parse_policy,
63  DefaultParsePolicy, policy_zstring_t>;
64  auto first = std::data( json_data );
65  auto last = daw::data_end( json_data );
66  if( first != last and last[-1] == 0 ) {
67  --last;
68  }
69  auto parse_state = ParseState( first, last );
70 
71  if constexpr( ParseState::must_verify_end_of_data_is_valid ) {
72  auto result =
73  json_details::parse_value<json_member, KnownBounds,
74  json_member::expected_type>( parse_state );
75  parse_state.trim_left( );
76  daw_json_ensure( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
77  parse_state );
78  return result;
79  } else {
80  return json_details::parse_value<json_member, KnownBounds,
81  json_member::expected_type>(
82  parse_state );
83  }
84  }
85 
94  template<typename JsonMember, bool KnownBounds, typename String>
95  [[nodiscard]] constexpr auto from_json( String &&json_data ) {
96  static_assert(
97  json_details::is_string_view_like_v<String>,
98  "String type must have a be a contiguous range of Characters" );
99  return from_json<JsonMember, KnownBounds>( DAW_FWD( json_data ),
100  options::parse_flags<> );
101  }
102 
111  template<typename JsonMember, bool KnownBounds, typename String,
112  typename Allocator, auto... PolicyFlags>
113  [[nodiscard]] constexpr auto
114  from_json_alloc( String &&json_data, Allocator const &alloc,
115  options::parse_flags_t<PolicyFlags...> ) {
116  static_assert(
117  json_details::is_string_view_like_v<String>,
118  "String type must have a be a contiguous range of Characters" );
119  daw_json_ensure( std::size( json_data ) != 0,
120  ErrorReason::EmptyJSONDocument );
121  daw_json_ensure( std::data( json_data ) != nullptr,
122  ErrorReason::EmptyJSONPath );
123 
124  using json_member = json_details::json_deduced_type<JsonMember>;
125 
126  static_assert(
127  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
128  "Missing specialization of daw::json::json_data_contract for class "
129  "mapping or specialization of daw::json::json_link_basic_type_map" );
130 
131  char const *f = std::data( json_data );
132  char const *l = daw::data_end( json_data );
133  Allocator a = alloc;
134 
135  using ParsePolicy =
136  BasicParsePolicy<options::parse_flags_t<PolicyFlags...>::value>;
137 
140  using ParseState = json_details::apply_zstring_policy_option_t<
141  ParsePolicy, String, options::ZeroTerminatedString::yes>;
142 
143  auto parse_state = ParseState::with_allocator( f, l, a );
144  if constexpr( ParseState::must_verify_end_of_data_is_valid ) {
145  auto result =
146  json_details::parse_value<json_member, KnownBounds,
147  json_member::expected_type>( parse_state );
148  parse_state.trim_left( );
149  daw_json_ensure( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
150  parse_state );
151  return result;
152  } else {
153  return json_details::parse_value<json_member, KnownBounds,
154  json_member::expected_type>(
155  parse_state );
156  }
157  }
158 
167  template<typename JsonMember, bool KnownBounds, typename String,
168  typename Allocator>
169  [[nodiscard]] constexpr auto from_json_alloc( String &&json_data,
170  Allocator const &alloc ) {
171  static_assert(
172  json_details::is_string_view_like_v<String>,
173  "String type must have a be a contiguous range of Characters" );
174  return from_json_alloc<JsonMember, KnownBounds>(
175  DAW_FWD( json_data ), alloc, options::parse_flags<> );
176  }
177 
188  template<typename JsonMember, bool KnownBounds, typename String,
189  auto... PolicyFlags>
190  [[nodiscard]] constexpr auto
191  from_json( String &&json_data, std::string_view member_path,
192  options::parse_flags_t<PolicyFlags...> ) {
193  static_assert(
194  json_details::is_string_view_like_v<String>,
195  "String type must have a be a contiguous range of Characters" );
196 
197  daw_json_ensure( std::size( json_data ) != 0,
198  ErrorReason::EmptyJSONDocument );
199  daw_json_ensure( std::data( json_data ) != nullptr,
200  ErrorReason::EmptyJSONPath );
201  daw_json_ensure( std::data( member_path ) != nullptr,
202  ErrorReason::EmptyJSONPath );
203 
204  using json_member = json_details::json_deduced_type<JsonMember>;
205  static_assert(
206  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
207  "Missing specialization of daw::json::json_data_contract for class "
208  "mapping or specialization of daw::json::json_link_basic_type_map" );
209 
210  using ParsePolicy =
211  BasicParsePolicy<options::parse_flags_t<PolicyFlags...>::value>;
212 
215  using policy_zstring_t = json_details::apply_zstring_policy_option_t<
216  ParsePolicy, String, options::ZeroTerminatedString::yes>;
217 
218  using ParseState =
219  daw::conditional_t<policy_zstring_t::is_default_parse_policy,
220  DefaultParsePolicy, policy_zstring_t>;
221  auto first = std::data( json_data );
222  auto last = daw::data_end( json_data );
223  if( first != last and last[-1] == 0 ) {
224  --last;
225  }
226  auto jv = basic_json_value( ParseState( first, last ) );
227  jv = jv.find_member( member_path );
228 
229  if constexpr( json_details::is_json_nullable_v<json_member> ) {
230  if( not jv ) {
231  return json_details::construct_nullable_empty<
232  json_details::json_constructor_t<json_member>>( );
233  }
234  } else {
235  daw_json_ensure( jv, ErrorReason::JSONPathNotFound );
236  }
237  auto parse_state = jv.get_raw_state( );
238  if constexpr( ParseState::must_verify_end_of_data_is_valid ) {
239  auto result =
240  json_details::parse_value<json_member, KnownBounds,
241  json_member::expected_type>( parse_state );
242  parse_state.trim_left( );
243  daw_json_ensure( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
244  parse_state );
245  return result;
246  } else {
247  return json_details::parse_value<json_member, KnownBounds,
248  json_member::expected_type>(
249  parse_state );
250  }
251  }
252 
263  template<typename JsonMember, bool KnownBounds, typename String>
264  [[nodiscard]] constexpr auto from_json( String &&json_data,
265  std::string_view member_path ) {
266  static_assert(
267  json_details::is_string_view_like_v<String>,
268  "String type must have a be a contiguous range of Characters" );
269 
270  return from_json<JsonMember, KnownBounds>(
271  DAW_FWD( json_data ), member_path, options::parse_flags<> );
272  }
273 
284  template<typename JsonMember, bool KnownBounds, typename String,
285  typename Allocator, auto... PolicyFlags>
286  [[nodiscard]] constexpr auto
287  from_json_alloc( String &&json_data, std::string_view member_path,
288  Allocator const &alloc,
289  options::parse_flags_t<PolicyFlags...> ) {
290 
291  static_assert(
292  json_details::is_string_view_like_v<String>,
293  "String type must have a be a contiguous range of Characters" );
294  daw_json_ensure( std::size( json_data ) != 0,
295  ErrorReason::EmptyJSONDocument );
296  daw_json_ensure( std::data( json_data ) != nullptr,
297  ErrorReason::EmptyJSONDocument );
298  daw_json_ensure( std::data( member_path ) != nullptr,
299  ErrorReason::EmptyJSONPath );
300 
301  using json_member = json_details::json_deduced_type<JsonMember>;
302  static_assert(
303  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
304  "Missing specialization of daw::json::json_data_contract for class "
305  "mapping or specialization of daw::json::json_link_basic_type_map" );
306 
307  using ParsePolicy =
308  BasicParsePolicy<options::parse_flags_t<PolicyFlags...>::value>;
309 
312  using ParseState = json_details::apply_zstring_policy_option_t<
313  ParsePolicy, String, options::ZeroTerminatedString::yes>;
314 
315  auto first = std::data( json_data );
316  auto last = daw::data_end( json_data );
317  if( first != last and last[-1] == 0 ) {
318  --last;
319  }
320  auto jv = basic_json_value(
321  ParseState( first, last, first, last ).with_allocator( alloc ) );
322  jv = jv.find_member( member_path );
323 
324  if constexpr( json_details::is_json_nullable_v<json_member> ) {
325  if( not jv ) {
326  return json_details::construct_nullable_empty<
327  json_details::json_constructor_t<json_member>>( );
328  }
329  } else {
330  daw_json_ensure( jv, ErrorReason::JSONPathNotFound );
331  }
332  auto parse_state = jv.get_raw_state( );
333  if constexpr( ParseState::must_verify_end_of_data_is_valid ) {
334  auto result =
335  json_details::parse_value<json_member, KnownBounds,
336  json_member::expected_type>( parse_state );
337  parse_state.trim_left( );
338  daw_json_ensure( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
339  parse_state );
340  return result;
341  } else {
342  return json_details::parse_value<json_member, KnownBounds,
343  json_member::expected_type>(
344  parse_state );
345  }
346  }
347 
358  template<typename JsonMember, bool KnownBounds, typename String,
359  typename Allocator>
360  [[nodiscard]] constexpr auto from_json_alloc( String &&json_data,
361  std::string_view member_path,
362  Allocator const &alloc ) {
363  static_assert(
364  json_details::is_string_view_like_v<String>,
365  "String type must have a be a contiguous range of Characters" );
366 
367  return from_json_alloc<JsonMember, KnownBounds>(
368  DAW_FWD( json_data ), member_path, alloc, options::parse_flags<> );
369  }
370 
378  template<typename JsonMember, bool KnownBounds, json_options_t P,
379  typename Allocator, auto... PolicyFlags>
380  [[nodiscard]] inline constexpr auto
382  options::parse_flags_t<PolicyFlags...> ) {
383  using json_member = json_details::json_deduced_type<JsonMember>;
384  static_assert(
385  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
386  "Missing specialization of daw::json::json_data_contract for class "
387  "mapping or specialization of daw::json::json_link_basic_type_map" );
388  using ParsePolicy = typename BasicParsePolicy<
389  P, Allocator>::template SetPolicyOptions<PolicyFlags...>;
390  using ParseState =
391  daw::conditional_t<ParsePolicy::is_default_parse_policy,
392  DefaultParsePolicy, ParsePolicy>;
393  auto const old_parse_state = value.get_raw_state( );
394  auto parse_state =
395  ParseState( old_parse_state.first, old_parse_state.last,
396  old_parse_state.class_first, old_parse_state.class_last,
397  old_parse_state.get_allocator( ) );
398 
399  return json_details::parse_value<json_member, KnownBounds,
400  json_member::expected_type>(
401  parse_state );
402  }
403 
411  template<typename JsonMember, bool KnownBounds, json_options_t PolicyFlags,
412  typename Allocator>
413  [[nodiscard]] inline constexpr auto
415 
416  return from_json<JsonMember, KnownBounds>( std::move( value ),
417  options::parse_flags<> );
418  }
419 
430  template<typename JsonMember, bool KnownBounds, json_options_t P,
431  typename Allocator, auto... PolicyFlags>
432  [[nodiscard]] constexpr auto
434  std::string_view member_path,
435  options::parse_flags_t<PolicyFlags...> ) {
436  using json_member = json_details::json_deduced_type<JsonMember>;
437  static_assert(
438  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
439  "Missing specialization of daw::json::json_data_contract for class "
440  "mapping or specialization of daw::json::json_link_basic_type_map" );
441  using ParsePolicy =
442  BasicParsePolicy<options::parse_flags_t<PolicyFlags...>::value>;
443  auto const old_parse_state = value.get_raw_state( );
444  using ParseState =
445  daw::conditional_t<ParsePolicy::is_default_parse_policy,
446  DefaultParsePolicy, ParsePolicy>;
447  auto jv = basic_json_value(
448  ParseState( old_parse_state.first, old_parse_state.last,
449  old_parse_state.class_first, old_parse_state.class_last,
450  old_parse_state.get_allocator( ) ) );
451 
452  jv = jv.find_member( member_path );
453 
454  if constexpr( json_details::is_json_nullable_v<json_member> ) {
455  if( not jv ) {
456  return json_details::construct_nullable_empty<
457  json_details::json_constructor_t<json_member>>( );
458  }
459  } else {
460  daw_json_ensure( jv, ErrorReason::JSONPathNotFound );
461  }
462  auto parse_state = jv.get_raw_state( );
463  return json_details::parse_value<json_member, KnownBounds,
464  json_member::expected_type>(
465  parse_state );
466  }
467 
478  template<typename JsonMember, bool KnownBounds, json_options_t PolicyFlags,
479  typename Allocator>
480  [[nodiscard]] constexpr auto from_json( basic_json_value<PolicyFlags> value,
481  std::string_view member_path ) {
482  return from_json<JsonMember, KnownBounds>(
483  std::move( value ), member_path, options::parse_flags<> );
484  }
485 
496  template<typename JsonElement, typename Container, typename Constructor,
497  bool KnownBounds, typename String, auto... PolicyFlags>
498  [[nodiscard]] constexpr Container
499  from_json_array( String &&json_data,
500  options::parse_flags_t<PolicyFlags...> ) {
501  static_assert(
502  json_details::is_string_view_like_v<String>,
503  "String type must have a be a contiguous range of Characters" );
504 
505  daw_json_ensure( std::size( json_data ) != 0,
506  ErrorReason::EmptyJSONDocument );
507  daw_json_ensure( std::data( json_data ) != nullptr,
508  ErrorReason::EmptyJSONPath );
509  static_assert(
510  json_details::has_unnamed_default_type_mapping_v<JsonElement>,
511  "Missing specialization of daw::json::json_data_contract for class "
512  "mapping or specialization of daw::json::json_link_basic_type_map" );
513  using element_type = json_details::json_deduced_type<JsonElement>;
514  static_assert( not std::is_same_v<element_type, void>,
515  "Unknown JsonElement type." );
516 
517  using parser_t =
518  json_base::json_array<JsonElement, Container, Constructor>;
519 
520  using ParsePolicy =
521  BasicParsePolicy<options::parse_flags_t<PolicyFlags...>::value>;
522 
525  using policy_zstring_t = json_details::apply_zstring_policy_option_t<
526  ParsePolicy, String, options::ZeroTerminatedString::yes>;
527 
528  using ParseState =
529  daw::conditional_t<policy_zstring_t::is_default_parse_policy,
530  DefaultParsePolicy, policy_zstring_t>;
531  auto parse_state =
532  ParseState{ std::data( json_data ), daw::data_end( json_data ) };
533 
534  parse_state.trim_left_unchecked( );
535 #if defined( DAW_JSON_BUGFIX_FROM_JSON_001 )
536  daw_json_ensure( parse_state.is_opening_bracket_checked( ),
537  ErrorReason::InvalidArrayStart, parse_state );
538 #else
539  daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
540  ErrorReason::InvalidArrayStart, parse_state );
541 #endif
542  if constexpr( ParseState::must_verify_end_of_data_is_valid ) {
543  auto result =
544  json_details::parse_value_array<parser_t, KnownBounds>( parse_state );
545  parse_state.trim_left( );
546  daw_json_ensure( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
547  parse_state );
548  return result;
549  } else {
550  return json_details::parse_value_array<parser_t, KnownBounds>(
551  parse_state );
552  }
553  }
554 
565  template<typename JsonElement, typename Container, typename Constructor,
566  bool KnownBounds, typename String>
567  [[nodiscard]] constexpr Container from_json_array( String &&json_data ) {
568  static_assert(
569  json_details::is_string_view_like_v<String>,
570  "String type must have a be a contiguous range of Characters" );
571  return from_json_array<JsonElement, Container, Constructor, KnownBounds>(
572  DAW_FWD( json_data ), options::parse_flags<> );
573  }
574 
588  template<typename JsonElement, typename Container, typename Constructor,
589  bool KnownBounds, typename String, auto... PolicyFlags>
590  [[nodiscard]] constexpr Container
591  from_json_array( String &&json_data, std::string_view member_path,
592  options::parse_flags_t<PolicyFlags...> ) {
593  static_assert(
594  json_details::is_string_view_like_v<String>,
595  "String type must have a be a contiguous range of Characters" );
596 
597  daw_json_ensure( std::size( json_data ) != 0,
598  ErrorReason::EmptyJSONDocument );
599  daw_json_ensure( std::data( json_data ) != nullptr,
600  ErrorReason::EmptyJSONPath );
601  daw_json_ensure( std::data( member_path ) != nullptr,
602  ErrorReason::EmptyJSONPath );
603  static_assert(
604  json_details::has_unnamed_default_type_mapping_v<JsonElement>,
605  "Missing specialization of daw::json::json_data_contract for class "
606  "mapping or specialization of daw::json::json_link_basic_type_map" );
607  using element_type = json_details::json_deduced_type<JsonElement>;
608  static_assert( not std::is_same_v<element_type, void>,
609  "Unknown JsonElement type." );
610 
611  using parser_t =
612  json_base::json_array<JsonElement, Container, Constructor>;
613 
614  using ParsePolicy =
615  BasicParsePolicy<options::parse_flags_t<PolicyFlags...>::value>;
616 
619  using policy_zstring_t = json_details::apply_zstring_policy_option_t<
620  ParsePolicy, String, options::ZeroTerminatedString::yes>;
621 
622  using ParseState =
623  daw::conditional_t<policy_zstring_t::is_default_parse_policy,
624  DefaultParsePolicy, policy_zstring_t>;
625  auto first = std::data( json_data );
626  auto last = daw::data_end( json_data );
627  if( first != last and last[-1] == 0 ) {
628  --last;
629  }
630  auto jv = basic_json_value( ParseState( first, last ) );
631  jv = jv.find_member( member_path );
632 
633  if constexpr( json_details::is_json_nullable_v<parser_t> ) {
634  if( not jv ) {
635  return json_details::construct_nullable_empty<
636  json_details::json_constructor_t<parser_t>>( );
637  }
638  } else {
639  daw_json_ensure( jv, ErrorReason::JSONPathNotFound );
640  }
641  auto parse_state = jv.get_raw_state( );
642  parse_state.trim_left_unchecked( );
643 #if defined( DAW_JSON_BUGFIX_FROM_JSON_001 )
644  daw_json_ensure( parse_state.is_opening_bracket_checked( ),
645  ErrorReason::InvalidArrayStart, parse_state );
646 #else
647  daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
648  ErrorReason::InvalidArrayStart, parse_state );
649 #endif
650  if constexpr( ParseState::must_verify_end_of_data_is_valid ) {
651  auto result =
652  json_details::parse_value_array<parser_t, KnownBounds>( parse_state );
653  parse_state.trim_left( );
654  daw_json_ensure( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
655  parse_state );
656  return result;
657  } else {
658  return json_details::parse_value_array<parser_t, KnownBounds>(
659  parse_state );
660  }
661  }
662 
676  template<typename JsonElement, typename Container, typename Constructor,
677  bool KnownBounds, typename String>
678  [[nodiscard]] constexpr Container
679  from_json_array( String &&json_data, std::string_view member_path ) {
680  static_assert(
681  json_details::is_string_view_like_v<String>,
682  "String type must have a be a contiguous range of Characters" );
683 
684  return from_json_array<JsonElement, Container, Constructor, KnownBounds>(
685  DAW_FWD( json_data ), member_path, options::parse_flags<> );
686  }
687  } // namespace DAW_JSON_VER
688 } // namespace daw::json
#define daw_json_assert_weak(Bool,...)
Assert that Bool is true when in Checked Input mode If false pass rest of args to daw_json_error.
#define daw_json_ensure(Bool,...)
Ensure that Bool is true. If false pass rest of args to daw_json_error.
constexpr Container from_json_array(String &&json_data, options::parse_flags_t< PolicyFlags... >)
Parse JSON data where the root item is an array.
constexpr auto from_json(String &&json_data, options::parse_flags_t< PolicyFlags... >)
Construct the JSONMember from the JSON document argument.
Definition: daw_from_json.h:39
constexpr auto from_json_alloc(String &&json_data, Allocator const &alloc, options::parse_flags_t< PolicyFlags... >)
Construct the JSONMember from the JSON document argument.
basic_json_value(BasicParsePolicy< PolicyFlags, Allocator >) -> basic_json_value< PolicyFlags, Allocator >
Customization point traits.
Handles the bounds and policy items for parsing execution and comments.
A non-owning container for arbitrary JSON values that allows movement/iteration through.
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25