DAW JSON Link
Loading...
Searching...
No Matches
daw_json_traits.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
12
22
23#include <daw/cpp_17.h>
24#include <daw/daw_callable.h>
25#include <daw/daw_cpp20_concept.h>
26#include <daw/daw_fwd_pack_apply.h>
27#include <daw/daw_move.h>
28#include <daw/daw_string_view.h>
29#include <daw/daw_traits.h>
30#include <daw/impl/daw_make_trait.h>
31
32#include <string>
33#include <string_view>
34#include <type_traits>
35
36namespace daw {
38 struct use_default;
39} // namespace daw
40
41/***
42 * Customization point traits
43 *
44 */
45namespace daw::json {
46 inline namespace DAW_JSON_VER {
47 namespace json_details {
48 template<template<typename...> typename Trait, typename... Params>
49 struct ident_trait {
50 using type = Trait<Params...>;
51 };
52
53 DAW_JSON_MAKE_REQ_TRAIT( has_op_bool_v,
54 static_cast<bool>( std::declval<T>( ) ) );
55
56 DAW_JSON_MAKE_REQ_TRAIT( has_op_star_v, *std::declval<T>( ) );
57
58 template<typename Constructor, typename... Args>
59 struct constructor_cannot_be_invoked;
60
61 template<typename Constructor, typename... Args>
62 struct construction_result
63 : daw::conditional_t<
64 daw::is_callable_v<Constructor, Args...>,
65 std::invoke_result<Constructor, Args...>,
66 daw::traits::identity<
67 constructor_cannot_be_invoked<Constructor, Args...>>> {};
68 } // namespace json_details
69
70 namespace json_details {
71 template<typename JsonMember>
72 using without_name = typename JsonMember::without_name;
73
74 template<typename JsonMember, JSONNAMETYPE NewName, bool Cond>
75 using copy_name_when = daw::conditional_t<
76 Cond, typename JsonMember::template with_name<NewName>, JsonMember>;
77
78 template<typename JsonMember, JSONNAMETYPE NewName>
79 using copy_name_when_noname =
80 copy_name_when<JsonMember, NewName, is_no_name_v<JsonMember>>;
81 } // namespace json_details
82
83 namespace json_details {
85 is_json_map_alias_v,
87
88 DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( has_switcher_v, T::switcher );
89
91 force_aggregate_construction_test1,
93
94 DAW_JSON_MAKE_REQ_TRAIT( force_aggregate_construction_test2,
95 T::force_aggregate_construction );
96 } // namespace json_details
97 /***
98 * This trait can be specialized such that when class being returned has
99 * non-move/copyable members the construction can be done with { } instead
100 * of a callable. This is a blunt object and probably should not be used
101 * add a type alias named force_aggregate_construction to your
102 * json_data_contract specialization
103 * @tparam T type to specialize
104 */
105 template<typename T>
106 inline constexpr bool force_aggregate_construction_v =
107 json_details::force_aggregate_construction_test1<T> or
108 json_details::force_aggregate_construction_test2<T>;
109
110 namespace json_details {
111 template<typename, typename = void>
112 struct json_constructor;
113
114 template<typename T>
115 struct json_constructor<T, std::void_t<typename T::constructor_t>> {
116 using type = typename T::constructor_t;
117 };
118
119 template<typename T>
120 using json_constructor_t = typename json_constructor<T>::type;
121
122 template<typename, typename = void>
123 struct json_result;
124
125 template<typename T>
126 struct json_result<T, std::void_t<typename T::parse_to_t>> {
127 using type = typename T::parse_to_t;
128 };
129
130 template<typename T>
131 using json_result_t = typename json_result<T>::type;
132
133 template<typename, typename = void>
134 struct json_base_type;
135
136 template<typename T>
137 struct json_base_type<T, std::void_t<json_result_t<T>>> {
138 using type = json_result_t<T>;
139 };
140
141 template<typename T>
142 using json_base_type_t = typename json_base_type<T>::type;
143
145 is_default_default_constructor_type_v,
146 T::i_am_the_default_default_constructor_type );
147
148 DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( has_stateless_allocator_v,
149 T::has_stateless_allocator );
150
152 has_data_contract_constructor_v, json_data_contract<T>::constructor_t );
153
154 template<typename>
155 inline constexpr bool must_be_class_member_v = false;
156 } // namespace json_details
157
158 template<typename Constructor, typename T, typename ParseState>
159 inline constexpr bool should_construct_explicitly_v =
160 not json_details::has_data_contract_constructor_v<T> and
161 ( force_aggregate_construction_v<T> or
162 json_details::is_default_default_constructor_type_v<Constructor> or
163 not json_details::has_stateless_allocator_v<ParseState> );
164
165 template<typename... Ts>
166 DAW_CPP20_CONCEPT is_empty_pack_v = sizeof...( Ts ) == 0;
167
174 template<typename>
175 inline constexpr bool can_single_allocation_string_v = false;
176
177 template<typename Char, typename CharTrait, typename Allocator>
178 inline constexpr bool can_single_allocation_string_v<
179 std::basic_string<Char, CharTrait, Allocator>> = true;
180
181 template<typename T>
183 std::bool_constant<can_single_allocation_string_v<T>>;
184
185 namespace json_details {
186 DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_a_json_type_v,
187 T::i_am_a_json_type );
188
189 template<typename... Ts>
190 inline constexpr bool are_json_types_v = ( is_a_json_type_v<Ts> and ... );
191
194 DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_an_ordered_member_v,
195 T::i_am_an_ordered_member );
196
197 template<typename T>
198 using is_an_ordered_member =
199 std::bool_constant<is_an_ordered_member_v<T>>;
200
201 DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_a_json_tagged_variant_v,
202 T::i_am_a_json_tagged_variant );
203
204 template<typename T>
205 using json_class_constructor_t_impl =
207
208 template<typename T>
209 using data_contract_constructor_t =
211
212 template<typename T, typename Default>
213 using json_class_constructor_t = daw::detected_or_t<
214 typename daw::conditional_t<
215 std::is_same_v<use_default, Default>,
216 daw::conditional_t<has_data_contract_constructor_v<T>,
217 ident_trait<data_contract_constructor_t, T>,
218 ident_trait<default_constructor, T>>,
219 daw::traits::identity<Default>>::type,
220 json_class_constructor_t_impl, T>;
221
223 is_string_view_like_v, ( (void)( std::data( std::declval<T>( ) ) ),
224 (void)( std::size( std::declval<T>( ) ) ) ) );
225
226 static_assert( is_string_view_like_v<std::string_view> );
227
228 } // namespace json_details
229
230 /***
231 * Trait for passively exploiting the zero termination when the type
232 * guarantees it.
233 */
234 template<typename>
235 inline constexpr bool is_zero_terminated_string_v = false;
236
237 template<typename CharT, typename Traits, typename Alloc>
238 inline constexpr bool
239 is_zero_terminated_string_v<std::basic_string<CharT, Traits, Alloc>> =
240 true;
241
242 template<typename T>
244 std::bool_constant<is_zero_terminated_string_v<T>>;
245
246 namespace json_details {
247 template<typename ParsePolicy, auto Option>
248 using apply_policy_option_t =
249 typename ParsePolicy::template SetPolicyOptions<Option>;
250
251 template<typename ParsePolicy, typename String, auto Option>
252 using apply_zstring_policy_option_t = daw::conditional_t<
253 is_zero_terminated_string_v<daw::remove_cvref_t<String>>,
254 apply_policy_option_t<ParsePolicy, Option>, ParsePolicy>;
255
259 template<typename ParsePolicy, typename String>
260 inline constexpr bool can_use_runtime_zstring_v =
261 daw::sv2::is_daw_string_view<String> and
262 not ParsePolicy::is_zero_terminated_string and
263 not ParsePolicy::is_unchecked_input and not ParsePolicy::has_allocator;
264
265 template<typename ParsePolicy>
266 using zstring_policy_t =
267 apply_policy_option_t<ParsePolicy, options::ZeroTerminatedString::yes>;
268
270 template<typename ParsePolicy, typename String>
271 [[nodiscard]] constexpr bool is_runtime_zstring( String const &json_data ) {
272 if constexpr( can_use_runtime_zstring_v<ParsePolicy, String> ) {
273 return json_data.is_zero_terminated( ) == daw::ZeroTerminated::Yes;
274 } else {
275 (void)json_data;
276 return false;
277 }
278 }
279
280 template<typename String>
281 inline constexpr bool is_mutable_string_v =
282 not std::is_const_v<std::remove_pointer_t<std::remove_reference_t<
283 decltype( std::data( std::declval<String &&>( ) ) )>>>;
284
285 /*
286 template<typename ParsePolicy, typename String, auto OptionMutable,
287 auto OptionImmutable>
288 using apply_mutable_policy = daw::conditional_t<
289 ParsePolicy::allow_temporarily_mutating_buffer( ),
290 daw::conditional_t<is_mutable_string_v<String>,
291 apply_policy_option_t<ParsePolicy, OptionMutable>,
292 apply_policy_option_t<ParsePolicy, OptionImmutable>>,
293 daw::conditional_t<
294 (is_rvalue_string<String> and is_mutable_string_v<String>),
295 apply_policy_option_t<ParsePolicy, OptionMutable>,
296 apply_policy_option_t<ParsePolicy, OptionImmutable>>>;
297 */
298 } // namespace json_details
299
300 /***
301 * Ignore unknown members trait allows the parser to skip unknown members
302 * when the default is exact
303 * Set to true when data contract has type alias ignore_unknown_members
304 */
306 ignore_unknown_members_v, json_data_contract<T>::ignore_unknown_members );
307
308 /***
309 * A trait to specify that this class, when parsed, will describe all
310 * members of the JSON object. Anything not mapped is an error.
311 * Either specialize this variable daw::json::is_exact_class_mapping_v, or
312 * have a type in your json_data_contract named exact_class_mapping for your
313 * type
314 */
316 is_exact_class_mapping_v, json_data_contract<T>::exact_class_mapping );
317
318 namespace json_details {
319 template<typename T, typename ParseState>
320 DAW_CPP20_CONCEPT all_json_members_must_exist_v =
321 not ignore_unknown_members_v<T> and
322 ( is_exact_class_mapping_v<T> or
323 ParseState::use_exact_mappings_by_default );
324
325 DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( has_element_type, T::element_type );
326
327 template<template<typename...> typename T, typename... Params>
328 struct identity_parts {
329 using type = T<Params...>;
330 };
331 } // namespace json_details
332
333 /***
334 * is_pointer_like is used in json_array to ensure that to_json_data returns
335 * a Container/View of the data with the size encoded with it.
336 * The std
337 */
338 template<typename T>
339 inline constexpr bool is_pointer_like_v =
340 std::is_pointer_v<T> or json_details::has_element_type<T>;
341
344 template<typename Tuple, typename = void>
346
347 template<typename... Ts>
348 struct tuple_elements_pack<std::tuple<Ts...>> {
349 using type = std::tuple<Ts...>;
350
351 static constexpr auto size = sizeof...( Ts );
352
353 template<std::size_t Idx>
354 using element_t = std::tuple_element_t<Idx, type>;
355
356 template<std::size_t Idx, typename Tuple>
357 static constexpr decltype( auto ) get( Tuple &&tp ) {
358 return std::get<Idx>( DAW_FWD( tp ) );
359 }
360 };
361
362 template<typename... Ts>
363 struct tuple_elements_pack<daw::fwd_pack<Ts...>> {
364 using type = daw::fwd_pack<Ts...>;
365
366 static constexpr auto size = sizeof...( Ts );
367
368 template<std::size_t Idx>
369 using element_t =
370 daw::remove_cvref_t<typename std::tuple_element_t<Idx, type>>;
371
372 template<std::size_t Idx, typename Tuple>
373 static constexpr decltype( auto ) get( Tuple &&tp ) {
374 return DAW_FWD( tp ).template get<Idx>( );
375 }
376 };
377
383 template<typename T>
384 inline constexpr bool is_pinned_type_v = not(
385 (std::is_copy_constructible_v<T> and std::is_copy_assignable_v<T>) or
386 ( std::is_move_constructible_v<T> and std::is_move_assignable_v<T> ) );
387
388 namespace json_details {
389 template<typename, typename = void>
390 inline constexpr bool is_tuple_v = false;
391
392 template<typename... Ts>
393 inline constexpr bool is_tuple_v<std::tuple<Ts...>> = true;
394
395 template<typename T>
396 inline constexpr bool
397 is_tuple_v<T, typename tuple_elements_pack<T>::type> = true;
398
399 template<typename T>
400 using unwrapped_t = concepts::nullable_value_type_t<T>;
401
402 template<typename T>
403 using mapped_type_t = typename T::mapped_type;
404
405 template<typename T>
406 using key_type_t = typename T::key_type;
407
408 // DAW disabling to fix #357
409#if true or defined( DAW_JSON_DISABLE_RANDOM )
410 template<bool>
411 DAW_CPP20_CONCEPT can_be_random_iterator_v = false;
412#else
413 template<bool IsKnown>
414 DAW_CPP20_CONCEPT can_be_random_iterator_v = IsKnown;
415#endif
416
417 DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_literal_json_type_v,
418 T::as_string );
419
420 template<typename JsonMember>
421 using literal_json_type_as_string = typename JsonMember::as_string;
422
423 DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_deduced_empty_class_v,
424 T::i_am_a_deduced_empty_class );
425
426 template<typename T>
427 struct ensure_mapped {
428 static_assert( is_a_json_type_v<T>,
429 "The supplied type does not have a json_data_contract" );
430 using type = T;
431 };
432
433 template<typename T>
434 using ensure_mapped_t = typename ensure_mapped<T>::type;
435
436 DAW_MAKE_REQ_TRAIT_TYPE( is_json_member_list_v,
437 T::i_am_a_json_member_list );
438
439 template<typename T>
440 using ordered_member_subtype_test = typename T::json_member;
441
442 template<typename T>
443 using ordered_member_subtype_t =
444 typename daw::detected_or_t<T, ordered_member_subtype_test, T>;
445
446 template<typename T, typename Default>
447 inline constexpr auto json_class_constructor =
448 json_class_constructor_t<T, Default>{ };
449
450 template<typename T>
451 using json_nullable_member_type_t = typename T::member_type;
452 } // namespace json_details
453 } // namespace DAW_JSON_VER
454} // namespace daw::json
#define DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT(Name,...)
#define DAW_JSON_MAKE_REQ_TRAIT(Name,...)
#define DAW_JSON_MAKE_REQ_TRAIT_CUSTOM(Name,...)
Disable concepts on gcc < 13.3. See https://github.com/beached/daw_json_link/issues/454.
#define DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT_CUSTOM(Name, ...)
typename json_data_contract< T >::type json_data_contract_trait_t
This trait gets us the mapping type from the contract.
constexpr bool can_single_allocation_string_v
Can use the fast, pseudo random string iterators. They are InputIterators with an operator- that allo...
constexpr bool is_pinned_type_v
Is the type pinned in memory and unable to be copied/moved after construction(e.g....
std::bool_constant< is_zero_terminated_string_v< T > > is_zero_terminated_string
std::bool_constant< can_single_allocation_string_v< T > > can_single_allocation_string
string_writer grows its string with resize_and_overwrite, leaving the new bytes uninitialized,...
Mapping class for JSON data structures to C++. It must be specialized in order to parse to a user cla...
daw::remove_cvref_t< typename std::tuple_element_t< Idx, type > > element_t
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20