DAW JSON Link
Loading...
Searching...
No Matches
daw_json_reflection.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/daw_pipelines.h"
12#include "daw_json_link.h"
13
14#include <cstddef>
15#include <experimental/meta>
16#include <tuple>
17#include <type_traits>
18#include <utility>
19#include <vector>
20
21#define DAW_REFL( ... ) ^^__VA_ARGS__
22#define DAW_SPLICE( ... ) [:__VA_ARGS__:]
23
25 inline namespace experimental {
26 template<typename E, json_options_t Options = json_custom_opts_def>
27 requires std::is_enum_v<E> struct enum_string;
28
29 struct refl_map_as {
30 std::meta::info type;
31 };
32
33 struct refl_rename {
34 char const *name;
35 };
36
40
42
43 template<typename T>
47
48 namespace refl_details {
49 template<auto... vals>
50 struct replicator_type {
51 template<typename F>
52 constexpr void operator>>( F body ) const {
53 ( body.template operator( )<vals>( ), ... );
54 }
55 };
56
57 template<auto... vals>
58 replicator_type<vals...> replicator = { };
59
61 consteval std::vector<std::meta::info>
62 pub_nsdm_of( std::meta::info type_class ) {
63 auto members = std::meta::nonstatic_data_members_of( type_class );
64 std::erase_if( members, []( std::meta::info const &i ) {
65 return not std::meta::is_public( i );
66 } );
67 return members;
68 }
69
70 template<typename R>
71 consteval auto expand( R range ) {
72 auto args = std::vector<std::meta::info>( );
73 for( auto r : range ) {
74 args.push_back( std::meta::reflect_value( r ) );
75 }
76 return std::meta::substitute( DAW_REFL( replicator ), args );
77 }
78
79 template<typename T>
80 consteval std::optional<T> get_annotaion( std::meta::info r ) {
81 for( std::meta::info a : std::meta::annotations_of( r ) ) {
82 if( std::meta::type_of( a ) == DAW_REFL( T ) ) {
83 return std::meta::extract<T>( a );
84 }
85 }
86 return std::nullopt;
87 }
88
89 template<typename T>
90 consteval bool has_annotation( std::meta::info r, T const &value ) {
91 auto expected = std::meta::reflect_value( value );
92 for( std::meta::info a : std::meta::annotations_of( r ) ) {
93 if( value_of( a ) == expected ) {
94 return true;
95 }
96 }
97 return false;
98 }
99
100 template<typename T, std::size_t... Is>
101 consteval auto to_tuple( T const &value, std::index_sequence<Is...> )
102 -> decltype( std::tuple(
103 value.DAW_SPLICE( pub_nsdm_of( DAW_REFL( T ) )[Is] )... ) ) {
104 return std::tuple(
105 value.DAW_SPLICE( pub_nsdm_of( DAW_REFL( T ) )[Is] )... );
106 }
107
108 template<typename T>
109 consteval auto
110 to_tuple( T const &value ) -> decltype( refl_details::to_tuple(
111 value,
112 std::make_index_sequence<pub_nsdm_of( DAW_REFL( T ) ).size( )>{ } ) ) {
113 return refl_details::to_tuple(
114 value,
115 std::make_index_sequence<pub_nsdm_of( DAW_REFL( T ) ).size( )>{ } );
116 }
117
118 template<JSONNAMETYPE Name, typename T>
119 using deduce_t = typename json_details::ensure_mapped_t<
120 json_details::json_deduced_type<T>>::template with_name<Name>;
121
122 template<typename T, std::size_t Idx>
123 using submember_type_t =
124 std::tuple_element_t<Idx, DAW_TYPEOF( refl_details::to_tuple(
125 std::declval<T>( ) ) )>;
126
127 template<typename T, std::size_t Idx>
128 consteval auto get_member_link_func( ) {
129 static constexpr auto member_info = pub_nsdm_of( DAW_REFL( T ) )[Idx];
130 static constexpr auto annot_rename =
131 get_annotaion<daw::json::refl_rename>( member_info );
132
133 static constexpr std::string_view name =
134 annot_rename ? std::string_view( annot_rename->name )
135 : std::meta::identifier_of( member_info );
136 static_assert( not name.empty( ), "Unexpected empty name" );
137
138 static constexpr auto annot_map_as = [] {
139 static constexpr auto refl_map_as_annot =
140 get_annotaion<refl_map_as>( member_info );
141 static constexpr auto refl_enum_string_annot =
142 get_annotaion<refl_enum_string>( member_info );
143 if constexpr( refl_map_as_annot ) {
144 static_assert( not refl_enum_string_annot,
145 "Do not use reflect.enum_string and reflect.map_as "
146 "at the same time" );
147 return refl_map_as_annot;
148 } else if constexpr( refl_enum_string_annot ) {
149 using json_member_no_name =
150 daw::json::enum_string<DAW_SPLICE(
151 std::meta::type_of( member_info ) ),
152 refl_enum_string_annot->Options>;
153 static constexpr auto info =
154 DAW_REFL( typename json_member_no_name::template with_name<
155 json_name<name.size( ) + 1>(
156 name.data( ),
157 std::make_index_sequence<name.size( ) + 1>{ } )> );
158 return std::optional<refl_map_as>{ refl_map_as{ info } };
159 } else {
160 return false;
161 }
162 }( );
163
164 if constexpr( annot_map_as ) {
165 static_assert(
166 not annot_rename,
167 "Do not use reflect.rename and reflect.map_as at the same time" );
168 static constexpr auto result =
169 daw::traits::identity<DAW_SPLICE( annot_map_as->type )>{ };
170 return result;
171 } else {
172 return daw::traits::identity<deduce_t<
173 json_name<name.size( ) + 1>(
174 name.data( ), std::make_index_sequence<name.size( ) + 1>{ } ),
175 submember_type_t<T, Idx>>>{ };
176 }
177 }
178
179 template<typename T, std::size_t Idx>
180 using get_member_link_t =
181 typename DAW_TYPEOF( get_member_link_func<T, Idx>( ) )::type;
182
183 template<typename, typename>
184 struct make_data_contract;
185
186 template<typename, typename...>
187 inline constexpr bool construction_test_v = false;
188
189 template<typename T, typename... Ts>
190 inline constexpr bool construction_test_v<T, std::tuple<Ts...>> =
191 requires {
192 T{ std::declval<Ts>( )... };
193 };
194
195 template<typename T>
196 concept Reflectable =
197 not std::is_empty_v<T> and std::is_class_v<T> and requires {
198 refl_details::to_tuple( std::declval<T>( ) );
199 }
200 and construction_test_v<T, DAW_TYPEOF( refl_details::to_tuple(
201 std::declval<T>( ) ) )>;
202
203 template<Reflectable T, std::size_t... Is>
204 struct make_data_contract<T, std::index_sequence<Is...>> {
205 using type = json_member_list<get_member_link_t<T, Is>...>;
206
207 DAW_ATTRIB_INLINE static constexpr auto to_json_data( T const &value ) {
208 return daw::forward_nonrvalue_as_tuple(
209 value.DAW_SPLICE( pub_nsdm_of( DAW_REFL( T ) )[Is] )... );
210 }
211 };
212
213 template<typename E>
214 requires std::is_enum_v<E> constexpr E
215 enum_from_string( std::string_view name ) {
216 template for( constexpr auto enumerator :
217 std::meta::enumerators_of( DAW_REFL( E ) ) ) {
218 if( name == std::meta::identifier_of( enumerator ) ) {
219 return DAW_SPLICE( enumerator );
220 }
221 }
222 daw_json_error( ErrorReason::InvalidString );
223 }
224
225 /*
226 template<typename E>
227 requires std::is_enum_v<E>
228 constexpr std::string_view enum_to_string( E value ) {
229 template for( constexpr auto enumerator: std::meta::enumerators_of(
230 DAW_REFL( E ) ) ) { if( value == DAW_SPLICE( enumerator ) ) { return
231 std::meta::identifier_of( enumerator );
232 }
233 }
234 return std::string_view{ };
235 }
236 */
237 template<typename E>
238 requires std::is_enum_v<E> constexpr std::string_view
239 enum_to_string( E value ) {
240 auto result = std::string_view{ };
241 DAW_SPLICE( expand( std::meta::enumerators_of( DAW_REFL( E ) ) ) ) >>
242 [&]<auto e> {
243 if( value == DAW_SPLICE( e ) ) {
244 result = std::meta::identifier_of( e );
245 }
246 };
247 return result;
248 }
249
250 template<typename E>
251 requires std::is_enum_v<E> struct reflect_enum_as_string {
252 static constexpr E operator( )( std::string_view name ) {
253 return enum_from_string<E>( name );
254 }
255
256 static constexpr std::string_view operator( )( E value ) {
257 return enum_to_string( value );
258 }
259 };
260 } // namespace refl_details
261
262 template<typename E, json_options_t Options>
263 requires std::is_enum_v<E> struct enum_string
264 : json_custom_no_name<E, refl_details::reflect_enum_as_string<E>,
265 refl_details::reflect_enum_as_string<E>, Options> {
266 };
267
268 inline constexpr struct reflect_t {
269 static consteval refl_rename rename( char const *name ) {
270 return refl_rename{ name };
271 }
272
273 template<typename JsonMember>
274 static constexpr auto map_as = refl_map_as{ DAW_REFL( JsonMember ) };
275
276 static constexpr auto ignore_with_default =
277 daw::json::refl_ignore_with_default{ };
278
279 template<typename T>
280 static consteval auto ignore_with_value( T &&v ) {
281 return refl_ignore_with_value{ DAW_FWD( v ) };
282 }
283
284 template<json_options_t Options>
285 static constexpr auto enum_string_with_opt =
286 daw::json::refl_enum_string{ Options };
287
288 static constexpr auto enum_string =
289 enum_string_with_opt<json_custom_opts_def>;
291
292 // Trait that specifies a type is to be reflected on for parse info
293 template<refl_details::Reflectable T>
294 inline constexpr bool is_reflectible_type_v =
295 refl_details::has_annotation( DAW_REFL( T ), reflect );
296 } // namespace experimental
297
298 template<typename T>
299 requires is_reflectible_type_v<T> //
301 : refl_details::make_data_contract<
302 T, std::make_index_sequence<
303 refl_details::pub_nsdm_of( DAW_REFL( T ) ).size( )>> {};
304
305} // namespace daw::json::inline DAW_JSON_VER
306
307#undef DAW_REFL
308#undef DAW_SPLICE
#define DAW_SPLICE(...)
#define DAW_REFL(...)
DAW_ATTRIB_NOINLINE void daw_json_error(ErrorReason reason)
constexpr struct daw::json::inline::experimental::reflect_t reflect
Mapping class for JSON data structures to C++. It must be specialized in order to parse to a user cla...
static consteval refl_rename rename(char const *name)
#define DAW_JSON_VER
The version string used in namespace definitions. Must be a valid namespace name.
Definition version.h:20