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
22namespace 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 ParseState =
63 json_details::apply_mutable_policy<policy_zstring_t, String,
66 auto parse_state =
67 ParseState( std::data( json_data ), daw::data_end( json_data ) );
68
69 if constexpr( ParseState::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,
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 ParseState =
127 json_details::apply_mutable_policy<policy_zstring_t, String,
130
131 auto parse_state = ParseState::with_allocator( f, l, a );
132 if constexpr( ParseState::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 ParseState =
189 json_details::apply_mutable_policy<policy_zstring_t, String,
192
193 auto [is_found, parse_state] = json_details::find_range<ParseState>(
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( ParseState::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 ParseState =
262 json_details::apply_mutable_policy<policy_zstring_t, String,
265
266 auto [is_found, parse_state] = json_details::find_range<ParseState>(
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( ParseState::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 ParseState =
403 json_details::apply_mutable_policy<policy_zstring_t, String,
406
407 auto [is_found, parse_state] = json_details::find_range<ParseState>(
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 daw_json_assert_weak( parse_state.is_opening_bracket_checked( ),
424 ErrorReason::InvalidArrayStart, parse_state );
425#endif
426 if constexpr( ParseState::must_verify_end_of_data_is_valid ) {
427 auto result = json_details::parse_value<parser_t, KnownBounds>(
429 parse_state.trim_left( );
430 daw_json_assert( parse_state.empty( ), ErrorReason::InvalidEndOfValue,
431 parse_state );
432 return result;
433 } else {
434 return json_details::parse_value<parser_t, KnownBounds>(
436 }
437 }
438 } // namespace DAW_JSON_VER
439} // namespace daw::json
Definition: daw_json_value.h:320
constexpr std::string_view get_string_view() const
Definition: daw_json_value.h:452
constexpr ParseState get_state() const
Definition: daw_json_value.h:462
#define daw_json_assert_weak(Bool,...)
Definition: daw_json_assert.h:190
#define daw_json_assert(Bool,...)
Definition: daw_json_assert.h:179
ParseState & parse_state
Definition: daw_json_parse_class.h:182
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:590
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:561
@ Null
An array with a fixed size. This allows for size_t/ptr like combinations.
daw::constant< v > ParseTag
Definition: daw_json_enums.h:119
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
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:16