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 "daw_from_json_fwd.h"
14 #include "impl/daw_json_value.h"
15 #include "impl/version.h"
16 
17 #include <daw/daw_traits.h>
18 
19 #include <iterator>
20 #include <string_view>
21 
22 namespace daw::json {
23  inline namespace DAW_JSON_VER {
34  template<typename JsonMember, typename ParsePolicy, bool KnownBounds,
35  typename Result, typename String>
36  [[maybe_unused, nodiscard]] constexpr auto from_json( String &&json_data )
37  -> std::enable_if_t<json_details::is_string_view_like_v<String>, Result> {
38 
39  daw_json_assert( std::data( json_data ) != nullptr,
40  ErrorReason::EmptyJSONPath );
41  daw_json_assert( std::size( json_data ) != 0,
42  ErrorReason::EmptyJSONDocument );
43 
44  static_assert(
45  json_details::has_json_deduced_type<JsonMember>::value,
46  "Missing specialization of daw::json::json_data_contract for class "
47  "mapping or specialization of daw::json::json_link_basic_type_map" );
48  using json_member = json_details::json_deduced_type<JsonMember>;
49 
50  /***
51  * If the string is known to have a trailing zero, allow optimization on
52  * that
53  */
54  using policy_zstring_t =
57 
58  /***
59  * In cases where we own the buffer or when requested and can, allow
60  * temporarily mutating it to reduce search costs
61  */
62  using checked_policy_t =
63  json_details::apply_mutable_policy<policy_zstring_t, String,
66  auto parse_state =
67  checked_policy_t( std::data( json_data ), daw::data_end( json_data ) );
68 
69  if constexpr( checked_policy_t::must_verify_end_of_data_is_valid ) {
70  auto result = json_details::parse_value<json_member, KnownBounds>(
72  parse_state.trim_left( );
73  daw_json_assert( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
74  parse_state );
75  return result;
76  } else {
77  return json_details::parse_value<json_member, KnownBounds>(
79  }
80  }
81 
92  template<typename JsonMember, typename ParsePolicy, bool KnownBounds,
93  typename Result, typename String, typename Allocator>
94  [[maybe_unused, nodiscard]] constexpr auto
95  from_json_alloc( String &&json_data, Allocator const &alloc )
96  -> std::enable_if_t<json_details::is_string_view_like_v<String>, Result> {
97 
98  daw_json_assert( std::size( json_data ) != 0,
99  ErrorReason::EmptyJSONDocument );
100  daw_json_assert( std::data( json_data ) != nullptr,
101  ErrorReason::EmptyJSONPath );
102 
103  using json_member = json_details::json_deduced_type<JsonMember>;
104 
105  static_assert(
106  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
107  "Missing specialization of daw::json::json_data_contract for class "
108  "mapping or specialization of daw::json::json_link_basic_type_map" );
109 
110  char const *f = std::data( json_data );
111  char const *l = daw::data_end( json_data );
112  Allocator a = alloc;
113 
114  /***
115  * If the string is known to have a trailing zero, allow optimization on
116  * that
117  */
118  using policy_zstring_t =
121 
122  /***
123  * In cases where we own the buffer or when requested and can, allow
124  * temporarily mutating it to reduce search costs
125  */
126  using checked_policy_t =
127  json_details::apply_mutable_policy<policy_zstring_t, String,
130 
131  auto parse_state = checked_policy_t::with_allocator( f, l, a );
132  if constexpr( checked_policy_t::must_verify_end_of_data_is_valid ) {
133  auto result = json_details::parse_value<json_member, KnownBounds>(
135  parse_state.trim_left( );
136  daw_json_assert( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
137  parse_state );
138  return result;
139  } else {
140  return json_details::parse_value<json_member, KnownBounds>(
142  }
143  }
144 
145  /***
146  * Parse a JSONMember from the json_data starting at member_path.
147  * @tparam JsonMember The type of the item being parsed
148  * @param json_data JSON string data
149  * @param member_path A dot separated path of member names, default is the
150  * root. Array indices are specified with square brackets e.g. [5] is the
151  * 6th item
152  * @tparam KnownBounds The bounds of the json_data are known to contain the
153  * whole value
154  * @return A value reified from the JSON data member
155  * @throws daw::json::json_exception
156  */
157  template<typename JsonMember, typename ParsePolicy, bool KnownBounds,
158  typename Result, typename String>
159  [[maybe_unused, nodiscard]] constexpr auto
160  from_json( String &&json_data, std::string_view member_path )
161  -> std::enable_if_t<json_details::is_string_view_like_v<String>, Result> {
162 
163  daw_json_assert( std::size( json_data ) != 0,
164  ErrorReason::EmptyJSONDocument );
165  daw_json_assert( std::data( json_data ) != nullptr,
166  ErrorReason::EmptyJSONPath );
167  daw_json_assert( std::data( member_path ) != nullptr,
168  ErrorReason::EmptyJSONPath );
169 
170  using json_member = json_details::json_deduced_type<JsonMember>;
171  static_assert(
172  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
173  "Missing specialization of daw::json::json_data_contract for class "
174  "mapping or specialization of daw::json::json_link_basic_type_map" );
175 
176  /***
177  * If the string is known to have a trailing zero, allow optimization on
178  * that
179  */
180  using policy_zstring_t =
183 
184  /***
185  * In cases where we own the buffer or when requested and can, allow
186  * temporarily mutating it to reduce search costs
187  */
188  using checked_policy_t =
189  json_details::apply_mutable_policy<policy_zstring_t, String,
192 
193  auto [is_found, parse_state] = json_details::find_range<checked_policy_t>(
194  json_data, { std::data( member_path ), std::size( member_path ) } );
195  if constexpr( json_member::expected_type == JsonParseTypes::Null ) {
196  if( not is_found ) {
197  return typename json_member::constructor_t{ }( );
198  }
199  } else {
200  daw_json_assert( is_found, ErrorReason::JSONPathNotFound );
201  }
202 
203  if constexpr( checked_policy_t::must_verify_end_of_data_is_valid ) {
204  auto result = json_details::parse_value<json_member, KnownBounds>(
206  parse_state.trim_left( );
207  daw_json_assert( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
208  parse_state );
209  return result;
210  } else {
211  return json_details::parse_value<json_member, KnownBounds>(
213  }
214  }
215 
216  /***
217  * Parse a JSONMember from the json_data starting at member_path.
218  * @tparam JsonMember The type of the item being parsed
219  * @param json_data JSON string data
220  * @param member_path A dot separated path of member names, default is the
221  * root. Array indices are specified with square brackets e.g. [5] is the
222  * 6th item
223  * @tparam KnownBounds The bounds of the json_data are known to contain the
224  * whole value
225  * @return A value reified from the JSON data member
226  * @throws daw::json::json_exception
227  */
228  template<typename JsonMember, typename ParsePolicy, bool KnownBounds,
229  typename Result, typename String, typename Allocator>
230  [[maybe_unused, nodiscard]] constexpr auto
231  from_json_alloc( String &&json_data, std::string_view member_path,
232  Allocator const &alloc )
233  -> std::enable_if_t<json_details::is_string_view_like_v<String>, Result> {
234 
235  daw_json_assert( std::size( json_data ) != 0,
236  ErrorReason::EmptyJSONDocument );
237  daw_json_assert( std::data( json_data ) != nullptr,
238  ErrorReason::EmptyJSONDocument );
239  daw_json_assert( std::data( member_path ) != nullptr,
240  ErrorReason::EmptyJSONPath );
241 
242  using json_member = json_details::json_deduced_type<JsonMember>;
243  static_assert(
244  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
245  "Missing specialization of daw::json::json_data_contract for class "
246  "mapping or specialization of daw::json::json_link_basic_type_map" );
247  Allocator a = alloc;
248 
249  /***
250  * If the string is known to have a trailing zero, allow optimization on
251  * that
252  */
253  using policy_zstring_t =
256 
257  /***
258  * In cases where we own the buffer or when requested and can, allow
259  * temporarily mutating it to reduce search costs
260  */
261  using checked_policy_t =
262  json_details::apply_mutable_policy<policy_zstring_t, String,
265 
266  auto [is_found, parse_state] = json_details::find_range<checked_policy_t>(
267  json_data, { std::data( member_path ), std::size( member_path ) }, a );
268  if constexpr( json_member::expected_type == JsonParseTypes::Null ) {
269  if( not is_found ) {
270  return typename json_member::constructor_t{ }( );
271  }
272  } else {
273  daw_json_assert( is_found, ErrorReason::JSONPathNotFound );
274  }
275 
276  if constexpr( checked_policy_t::must_verify_end_of_data_is_valid ) {
277  auto result = json_details::parse_value<json_member, KnownBounds>(
279  parse_state.trim_left( );
280  daw_json_assert( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
281  parse_state );
282  return result;
283  } else {
284  return json_details::parse_value<json_member, KnownBounds>(
286  }
287  }
288 
289  /***
290  * Parse a value from a json_value
291  * @tparam JsonMember The type of the item being parsed
292  * @param value JSON data, see basic_json_value
293  * @tparam KnownBounds The bounds of the json_data are known to contain the
294  * whole value
295  * @return A value reified from the JSON data member
296  * @throws daw::json::json_exception
297  */
298  template<typename JsonMember, typename ParsePolicy, bool KnownBounds,
299  typename Result, typename ParseState>
300  [[maybe_unused, nodiscard]] inline constexpr Result
302  using json_member = json_details::json_deduced_type<JsonMember>;
303  static_assert(
304  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
305  "Missing specialization of daw::json::json_data_contract for class "
306  "mapping or specialization of daw::json::json_link_basic_type_map" );
307  auto const json_data = value.get_string_view( );
308  auto parse_state =
309  ParsePolicy( std::data( json_data ), daw::data_end( json_data ) );
310 
311  return json_details::parse_value<json_member, KnownBounds>(
313  }
314 
315  /***
316  * Parse a JSONMember from the json_data starting at member_path.
317  * @param value JSON data, see basic_json_value
318  * @param member_path A dot separated path of member names, default is the
319  * root. Array indices are specified with square brackets e.g. [5] is the
320  * 6th item
321  * @tparam JsonMember The type of the item being parsed
322  * @tparam KnownBounds The bounds of the json_data are known to contain the
323  * whole value
324  * @return A value reified from the JSON data member
325  * @throws daw::json::json_exception
326  */
327  template<typename JsonMember, typename ParsePolicy, bool KnownBounds,
328  typename Result, typename ParseState>
329  [[maybe_unused, nodiscard]] constexpr Result
331  std::string_view member_path ) {
332  using json_member = json_details::json_deduced_type<JsonMember>;
333  static_assert(
334  json_details::has_unnamed_default_type_mapping_v<JsonMember>,
335  "Missing specialization of daw::json::json_data_contract for class "
336  "mapping or specialization of daw::json::json_link_basic_type_map" );
337  auto json_data = value.get_state( );
338  auto [is_found, parse_state] = json_details::find_range<ParsePolicy>(
339  json_data, { std::data( member_path ), std::size( member_path ) } );
340  if constexpr( json_member::expected_type == JsonParseTypes::Null ) {
341  if( not is_found ) {
342  return typename json_member::constructor_t{ }( );
343  }
344  } else {
345  daw_json_assert( is_found, ErrorReason::JSONPathNotFound );
346  }
347  return json_details::parse_value<json_member, KnownBounds>(
349  }
350 
366  template<typename JsonElement, typename Container, typename ParsePolicy,
367  typename Constructor, bool KnownBounds, typename String>
368  [[maybe_unused, nodiscard]] constexpr auto
369  from_json_array( String &&json_data, std::string_view member_path )
370  -> std::enable_if_t<json_details::is_string_view_like_v<String>,
371  Container> {
372 
373  daw_json_assert( std::size( json_data ) != 0,
374  ErrorReason::EmptyJSONDocument );
375  daw_json_assert( std::data( json_data ) != nullptr,
376  ErrorReason::EmptyJSONPath );
377  daw_json_assert( std::data( member_path ) != nullptr,
378  ErrorReason::EmptyJSONPath );
379  static_assert(
380  json_details::has_unnamed_default_type_mapping_v<JsonElement>,
381  "Missing specialization of daw::json::json_data_contract for class "
382  "mapping or specialization of daw::json::json_link_basic_type_map" );
383  using element_type = json_details::json_deduced_type<JsonElement>;
384  static_assert( traits::not_same<element_type, void>::value,
385  "Unknown JsonElement type." );
386 
387  using parser_t =
388  json_base::json_array<JsonElement, Container, Constructor>;
389 
390  /***
391  * If the string is known to have a trailing zero, allow optimization on
392  * that
393  */
394  using policy_zstring_t =
397 
398  /***
399  * In cases where we own the buffer or when requested and can, allow
400  * temporarily mutating it to reduce search costs
401  */
402  using checked_policy_t =
403  json_details::apply_mutable_policy<policy_zstring_t, String,
406 
407  auto [is_found, parse_state] = json_details::find_range<checked_policy_t>(
408  json_data, { std::data( member_path ), std::size( member_path ) } );
409 
410  if constexpr( parser_t::expected_type == JsonParseTypes::Null ) {
411  if( not is_found ) {
412  return typename parser_t::constructor_t{ }( );
413  }
414  } else {
415  daw_json_assert( is_found, ErrorReason::JSONPathNotFound );
416  }
417  parse_state.trim_left_unchecked( );
418 #if defined( _MSC_VER ) and not defined( __clang__ )
419  // Work around MSVC ICE
420  daw_json_assert( parse_state.is_opening_bracket_checked( ),
421  ErrorReason::InvalidArrayStart, parse_state );
422 #else
423  using ParseState = daw::remove_cvref_t<decltype( parse_state )>;
424  daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
425  ErrorReason::InvalidArrayStart, parse_state );
426 #endif
427  if constexpr( checked_policy_t::must_verify_end_of_data_is_valid ) {
428  auto result = json_details::parse_value<parser_t, KnownBounds>(
430  parse_state.trim_left( );
431  daw_json_assert( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
432  parse_state );
433  return result;
434  } else {
435  return json_details::parse_value<parser_t, KnownBounds>(
437  }
438  }
439  } // namespace DAW_JSON_VER
440 } // namespace daw::json
Definition: daw_json_value.h:316
constexpr std::string_view get_string_view() const
Definition: daw_json_value.h:444
constexpr ParseState get_state() const
Definition: daw_json_value.h:454
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:189
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:178
ParseState & parse_state
Definition: daw_json_parse_class.h:201
std::conditional_t< ParsePolicy::allow_temporarily_mutating_buffer, std::conditional_t< is_mutable_string_v< String >, apply_policy_option_t< ParsePolicy, OptionMutable >, apply_policy_option_t< ParsePolicy, OptionImmutable > >, std::conditional_t<(is_rvalue_string< String > and is_mutable_string_v< String >), apply_policy_option_t< ParsePolicy, OptionMutable >, apply_policy_option_t< ParsePolicy, OptionImmutable > >> apply_mutable_policy
Definition: daw_json_traits.h:555
std::conditional_t< is_zero_terminated_string_v< daw::remove_cvref_t< String > >, apply_policy_option_t< ParsePolicy, Option >, ParsePolicy > apply_zstring_policy_option_t
Definition: daw_json_traits.h:526
std::integral_constant< JsonParseTypes, v > ParseTag
Definition: daw_json_enums.h:106
constexpr auto from_json_alloc(String &&json_data, Allocator const &alloc) -> std::enable_if_t< json_details::is_string_view_like_v< String >, Result >
Definition: daw_from_json.h:95
constexpr auto from_json_array(String &&json_data, std::string_view member_path) -> std::enable_if_t< json_details::is_string_view_like_v< String >, Container >
Definition: daw_from_json.h:369
constexpr auto from_json(String &&json_data) -> std::enable_if_t< json_details::is_string_view_like_v< String >, Result >
Definition: daw_from_json.h:36
Definition: daw_from_json.h:22
#define DAW_JSON_VER
Definition: version.h:11