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