DAW JSON Link
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 
11 #include "version.h"
12 
14 #include "daw_json_enums.h"
16 #include "daw_json_name.h"
17 #include "daw_json_req_helper.h"
20 
21 #include <daw/cpp_17.h>
22 #include <daw/daw_fwd_pack_apply.h>
23 #include <daw/daw_move.h>
24 #include <daw/daw_traits.h>
25 
26 #include <string>
27 #include <string_view>
28 #include <type_traits>
29 
30 namespace daw {
32  struct use_default;
33 } // namespace daw
34 
35 /***
36  * Customization point traits
37  *
38  */
39 namespace daw::json {
40  inline namespace DAW_JSON_VER {
41  namespace json_details {
42  template<template<typename...> typename Trait, typename... Params>
43  struct ident_trait {
44  using type = Trait<Params...>;
45  };
46 
47  DAW_JSON_MAKE_REQ_TRAIT( has_op_bool_v,
48  static_cast<bool>( std::declval<T>( ) ) );
49 
50  DAW_JSON_MAKE_REQ_TRAIT( has_op_star_v, *std::declval<T>( ) );
51 
52  template<typename Constructor, typename... Args>
53  struct constructor_cannot_be_invoked;
54 
55  template<typename Constructor, typename... Args>
56  struct construction_result
57  : daw::conditional_t<
58  std::is_invocable_v<Constructor, Args...>,
59  std::invoke_result<Constructor, Args...>,
60  daw::traits::identity<
61  constructor_cannot_be_invoked<Constructor, Args...>>> {};
62  } // namespace json_details
63 
64  namespace json_details {
65  template<typename JsonMember>
66  using without_name = typename JsonMember::without_name;
67 
68  template<typename JsonMember, JSONNAMETYPE NewName, bool Cond>
69  using copy_name_when = daw::conditional_t<
70  Cond, typename JsonMember::template with_name<NewName>, JsonMember>;
71 
72  template<typename JsonMember, JSONNAMETYPE NewName>
73  using copy_name_when_noname =
74  copy_name_when<JsonMember, NewName, is_no_name_v<JsonMember>>;
75  } // namespace json_details
76 
77  namespace json_details {
79  is_json_map_alias_v,
81 
82  DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( has_switcher_v, T::switcher );
83 
85  force_aggregate_construction_test1,
87 
88  DAW_JSON_MAKE_REQ_TRAIT( force_aggregate_construction_test2,
89  T::force_aggregate_construction );
90  } // namespace json_details
91  /***
92  * This trait can be specialized such that when class being returned has
93  * non-move/copyable members the construction can be done with { } instead
94  * of a callable. This is a blunt object and probably should not be used
95  * add a type alias named force_aggregate_construction to your
96  * json_data_contract specialization
97  * @tparam T type to specialize
98  */
99  template<typename T>
100  inline constexpr bool force_aggregate_construction_v =
101  json_details::force_aggregate_construction_test1<T> or
102  json_details::force_aggregate_construction_test2<T>;
103 
104  namespace json_details {
105  template<typename, typename = void>
106  struct json_constructor;
107 
108  template<typename T>
109  struct json_constructor<T, std::void_t<typename T::constructor_t>> {
110  using type = typename T::constructor_t;
111  };
112 
113  template<typename T>
114  using json_constructor_t = typename json_constructor<T>::type;
115 
116  template<typename, typename = void>
117  struct json_result;
118 
119  template<typename T>
120  struct json_result<T, std::void_t<typename T::parse_to_t>> {
121  using type = typename T::parse_to_t;
122  };
123 
124  template<typename T>
125  using json_result_t = typename json_result<T>::type;
126 
127  template<typename, typename = void>
128  struct json_base_type;
129 
130  template<typename T>
131  struct json_base_type<T, std::void_t<json_result_t<T>>> {
132  using type = json_result_t<T>;
133  };
134 
135  template<typename T>
136  using json_base_type_t = typename json_base_type<T>::type;
137 
139  is_default_default_constructor_type_v,
140  T::i_am_the_default_default_constructor_type );
141 
142  DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( has_stateless_allocator_v,
143  T::has_stateless_allocator );
144 
146  has_data_contract_constructor_v, json_data_contract<T>::constructor_t );
147 
148  template<typename>
149  inline constexpr bool must_be_class_member_v = false;
150  } // namespace json_details
151 
152  template<typename Constructor, typename T, typename ParseState>
153  inline constexpr bool should_construct_explicitly_v =
154  not json_details::has_data_contract_constructor_v<T> and
155  ( force_aggregate_construction_v<T> or
156  json_details::is_default_default_constructor_type_v<Constructor> or
157  not json_details::has_stateless_allocator_v<ParseState> );
158 
159  template<typename... Ts>
160  inline constexpr bool is_empty_pack_v = sizeof...( Ts ) == 0;
161 
168  template<typename>
169  inline constexpr bool can_single_allocation_string_v = false;
170 
171  template<typename Char, typename CharTrait, typename Allocator>
172  inline constexpr bool can_single_allocation_string_v<
173  std::basic_string<Char, CharTrait, Allocator>> = true;
174 
175  template<typename T>
177  std::bool_constant<can_single_allocation_string_v<T>>;
178 
179  namespace json_details {
180  DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_a_json_type_v,
181  T::i_am_a_json_type );
182 
183  template<typename... Ts>
184  inline constexpr bool are_json_types_v = ( is_a_json_type_v<Ts> and ... );
185 
186  DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_an_ordered_member_v,
187  T::i_am_an_ordered_member );
188 
189  template<typename T>
190  using is_an_ordered_member =
191  std::bool_constant<is_an_ordered_member_v<T>>;
192 
193  DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_a_json_tagged_variant_v,
194  T::i_am_a_json_tagged_variant );
195 
196  template<typename T>
197  using json_class_constructor_t_impl =
199 
200  template<typename T>
201  using data_contract_constructor_t =
203 
204  template<typename T, typename Default>
205  using json_class_constructor_t = daw::detected_or_t<
206  typename daw::conditional_t<
207  std::is_same_v<use_default, Default>,
208  daw::conditional_t<has_data_contract_constructor_v<T>,
209  ident_trait<data_contract_constructor_t, T>,
210  ident_trait<default_constructor, T>>,
211  daw::traits::identity<Default>>::type,
212  json_class_constructor_t_impl, T>;
213 
214  DAW_JSON_MAKE_REQ_TRAIT( is_string_view_like_v,
215  ( (void)( std::data( std::declval<T>( ) ) ),
216  (void)( std::size( std::declval<T>( ) ) ) ) );
217 
218  static_assert( is_string_view_like_v<std::string_view> );
219 
220  } // namespace json_details
221 
222  /***
223  * Trait for passively exploiting the zero termination when the type
224  * guarantees it.
225  */
226  template<typename>
227  inline constexpr bool is_zero_terminated_string_v = false;
228 
229  template<typename CharT, typename Traits, typename Alloc>
230  inline constexpr bool
231  is_zero_terminated_string_v<std::basic_string<CharT, Traits, Alloc>> =
232  true;
233 
234  template<typename T>
236  std::bool_constant<is_zero_terminated_string_v<T>>;
237 
238  namespace json_details {
239  template<typename ParsePolicy, auto Option>
240  using apply_policy_option_t =
241  typename ParsePolicy::template SetPolicyOptions<Option>;
242 
243  template<typename ParsePolicy, typename String, auto Option>
244  using apply_zstring_policy_option_t = daw::conditional_t<
245  is_zero_terminated_string_v<daw::remove_cvref_t<String>>,
246  apply_policy_option_t<ParsePolicy, Option>, ParsePolicy>;
247 
248  template<typename String>
249  inline constexpr bool is_mutable_string_v =
250  not std::is_const_v<std::remove_pointer_t<std::remove_reference_t<
251  decltype( std::data( std::declval<String &&>( ) ) )>>>;
252 
253  template<typename String>
254  constexpr bool is_mutable_string =
255  json_details::is_mutable_string_v<String>;
256 
257  template<typename String>
258  constexpr bool is_rvalue_string = std::is_rvalue_reference_v<String>;
259 
260  template<typename String>
261  constexpr bool is_ref_string =
262  not is_rvalue_string<String> and
263  std::is_const_v<std::remove_reference_t<String>>;
264 
265  /*
266  template<typename ParsePolicy, typename String, auto OptionMutable,
267  auto OptionImmutable>
268  using apply_mutable_policy = daw::conditional_t<
269  ParsePolicy::allow_temporarily_mutating_buffer( ),
270  daw::conditional_t<is_mutable_string_v<String>,
271  apply_policy_option_t<ParsePolicy, OptionMutable>,
272  apply_policy_option_t<ParsePolicy, OptionImmutable>>,
273  daw::conditional_t<
274  (is_rvalue_string<String> and is_mutable_string_v<String>),
275  apply_policy_option_t<ParsePolicy, OptionMutable>,
276  apply_policy_option_t<ParsePolicy, OptionImmutable>>>;
277  */
278  } // namespace json_details
279 
280  /***
281  * Ignore unknown members trait allows the parser to skip unknown members
282  * when the default is exact
283  * Set to true when data contract has type alias ignore_unknown_members
284  */
286  ignore_unknown_members_v, json_data_contract<T>::ignore_unknown_members );
287 
288  /***
289  * A trait to specify that this class, when parsed, will describe all
290  * members of the JSON object. Anything not mapped is an error.
291  * Either specialize this variable daw::json::is_exact_class_mapping_v, or
292  * have a type in your json_data_contract named exact_class_mapping for your
293  * type
294  */
296  is_exact_class_mapping_v, json_data_contract<T>::exact_class_mapping );
297 
298  namespace json_details {
299  template<typename T, typename ParseState>
300  inline constexpr bool all_json_members_must_exist_v =
301  not ignore_unknown_members_v<T> and
302  ( is_exact_class_mapping_v<T> or
303  ParseState::use_exact_mappings_by_default );
304 
305  DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( has_element_type, T::element_type );
306 
307  template<template<typename...> typename T, typename... Params>
308  struct identity_parts {
309  using type = T<Params...>;
310  };
311  } // namespace json_details
312 
313  /***
314  * is_pointer_like is used in json_array to ensure that to_json_data returns
315  * a Container/View of the data with the size encoded with it.
316  * The std
317  */
318  template<typename T>
319  inline constexpr bool is_pointer_like_v =
320  std::is_pointer_v<T> or json_details::has_element_type<T>;
321 
324  template<typename Tuple, typename = void>
326 
327  template<typename... Ts>
328  struct tuple_elements_pack<std::tuple<Ts...>> {
329  using type = std::tuple<Ts...>;
330 
331  static constexpr std::size_t size = sizeof...( Ts );
332 
333  template<std::size_t Idx>
334  using element_t = std::tuple_element_t<Idx, type>;
335 
336  template<std::size_t Idx, typename Tuple>
337  static constexpr decltype( auto ) get( Tuple &&tp ) {
338  return std::get<Idx>( DAW_FWD( tp ) );
339  }
340  };
341 
342  template<typename... Ts>
343  struct tuple_elements_pack<daw::fwd_pack<Ts...>> {
344  using type = daw::fwd_pack<Ts...>;
345 
346  static constexpr std::size_t size = sizeof...( Ts );
347 
348  template<std::size_t Idx>
349  using element_t =
350  daw::remove_cvref_t<typename daw::tuple_element<Idx, type>::type>;
351 
352  template<std::size_t Idx, typename Tuple>
353  static constexpr decltype( auto ) get( Tuple &&tp ) {
354  return DAW_FWD( tp ).template get<Idx>( );
355  }
356  };
357 
363  template<typename T>
364  inline constexpr bool is_pinned_type_v = not(
365  (std::is_copy_constructible_v<T> and std::is_copy_assignable_v<T>) or
366  ( std::is_move_constructible_v<T> and std::is_move_assignable_v<T> ) );
367 
368  namespace json_details {
369  template<typename, typename = void>
370  inline constexpr bool is_tuple_v = false;
371 
372  template<typename... Ts>
373  inline constexpr bool is_tuple_v<std::tuple<Ts...>> = true;
374 
375  template<typename T>
376  inline constexpr bool
377  is_tuple_v<T, typename tuple_elements_pack<T>::type> = true;
378 
379  template<typename T>
380  using unwrapped_t = concepts::nullable_value_type_t<T>;
381 
382  template<typename T>
383  using mapped_type_t = typename T::mapped_type;
384 
385  template<typename T>
386  using key_type_t = typename T::key_type;
387 
388 // DAW disabling to fix #357
389 #if true or defined( DAW_JSON_DISABLE_RANDOM )
390  template<bool>
391  inline constexpr bool can_be_random_iterator_v = false;
392 #else
393  template<bool IsKnown>
394  inline constexpr bool can_be_random_iterator_v = IsKnown;
395 #endif
396 
397  DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT( is_literal_json_type_v,
398  T::as_string );
399 
400  template<typename JsonMember>
401  using literal_json_type_as_string = typename JsonMember::as_string;
402 
403  template<typename, typename = void>
404  inline constexpr bool is_deduced_empty_class_v = false;
405  } // namespace json_details
406  } // namespace DAW_JSON_VER
407 } // namespace daw::json
#define DAW_JSON_MAKE_REQ_TRAIT(Name,...)
Disable concepts on gcc < 13.3. See https://github.com/beached/daw_json_link/issues/454.
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....
DAW_JSON_MAKE_REQ_TYPE_ALIAS_TRAIT(ignore_unknown_members_v, json_data_contract< T >::ignore_unknown_members)
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
constexpr decltype(auto) get(basic_json_pair< PolicyFlags, Allocator > const &parse_state)
Customization point traits.
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 daw::tuple_element< Idx, type >::type > element_t
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition: version.h:25