LeviLamina
Loading...
Searching...
No Matches
Reflection.h
1#pragma once
2
3#include <array>
4#include <cctype>
5#include <cstddef>
6#include <optional>
7#include <type_traits>
8#include <utility>
9
10#include "ll/api/Expected.h"
11#include "ll/api/base/Concepts.h"
12#include "ll/api/base/Meta.h"
13#include "ll/api/reflection/Serializer.h"
14#include "ll/api/reflection/TypeName.h"
15#include "ll/api/utils/StringUtils.h"
16
17#if defined(__clang__) && !defined(BOOST_PFR_CORE_NAME_PARSING)
18#define BOOST_PFR_CORE_NAME_PARSING \
19 (sizeof("auto boost::pfr::detail::name_of_field_impl() [MsvcWorkaround = ") - 1, sizeof("}]") - 1, backward("."))
20
21#endif
22
23#include "boost/pfr.hpp"
24
25#include "magic_enum/magic_enum_all.hpp"
26
27namespace ll::reflection {
28template <class T>
29constexpr bool is_reflectable_v =
30 std::is_aggregate_v<std::remove_cvref_t<T>> && !traits::is_std_array_v<std::remove_cvref_t<T>>;
31
32template <class T>
33concept Reflectable = is_reflectable_v<T>;
34
35namespace detail {
36template <typename F>
37constexpr bool is_key_formatter_v = requires(F f, std::string_view sv) {
38 { f(sv) } -> std::convertible_to<std::string>;
39} || requires(F f, std::string_view sv) {
40 { f(sv) } -> std::convertible_to<std::string_view>;
41};
42
43constexpr auto default_key_formatter = [](std::string_view sv) -> std::string_view { return sv; };
44
45template <typename T>
46constexpr bool is_string_serializable_v = requires(T const& t, std::string_view sv) {
47 { reflection::Serializer<T>::to_string(t) } -> std::convertible_to<std::string>;
48 { reflection::Serializer<T>::from_string(sv) } -> std::convertible_to<ll::Expected<T>>;
49};
50
51template <typename T>
52constexpr bool is_key_stringifiable_v =
53 is_string_serializable_v<T> || traits::is_string_convertible_v<T> || std::is_enum_v<T>;
54
55template <typename T, typename F>
56constexpr bool has_custom_key_serializer_v = requires(T const& t, F const& f) {
57 { Serializer<T>::to_string(t, f) } -> std::convertible_to<std::string>;
58} || requires(T const& t) {
59 { Serializer<T>::to_string(t) } -> std::convertible_to<std::string>;
60};
61
62template <typename T, typename F>
63constexpr bool has_typed_key_formatter_v = requires(T const& t, F const& f) {
64 { f.template operator()<std::remove_cvref_t<T>>(t) } -> std::convertible_to<std::string>;
65};
66
67template <typename T, typename F>
68constexpr bool has_custom_key_deserializer_v = requires(std::string_view sv, F const& f) {
69 { Serializer<T>::from_string(sv, f) } -> std::convertible_to<ll::Expected<T>>;
70} || requires(std::string_view sv) {
71 { Serializer<T>::from_string(sv) } -> std::convertible_to<ll::Expected<T>>;
72};
73
74template <typename T, typename J, typename F>
75constexpr bool has_value_serializer_v = requires(T const& t, F const& f) {
76 { Serializer<std::remove_cvref_t<T>, std::remove_cvref_t<J>>::serialize(t, f) };
77} || requires(T const& t) {
78 { Serializer<std::remove_cvref_t<T>, std::remove_cvref_t<J>>::serialize(t) };
79} || requires(T const& t, F const& f) {
80 { Serializer<std::remove_cvref_t<T>>::template serialize<std::remove_cvref_t<J>>(t, f) };
81} || requires(T const& t) {
82 { Serializer<std::remove_cvref_t<T>>::template serialize<std::remove_cvref_t<J>>(t) };
83};
84
85template <typename T, typename J, typename F>
86constexpr bool has_inplace_serializer_v = requires(T const& t, std::remove_cvref_t<J>& j, F const& f) {
87 { Serializer<T>::serialize(t, j, f) } -> std::convertible_to<ll::Expected<>>;
88} || requires(T const& t, std::remove_cvref_t<J>& j) {
89 { Serializer<T>::serialize(t, j) } -> std::convertible_to<ll::Expected<>>;
90};
91
92template <typename T, typename J, typename F>
93constexpr bool has_custom_serializer_v = has_value_serializer_v<T, J, F> || has_inplace_serializer_v<T, J, F>;
94
95template <typename T, typename J, typename F>
96constexpr bool has_value_deserializer_v = requires(std::remove_cvref_t<J> const& j, F const& f) {
97 { Serializer<std::remove_cvref_t<T>, std::remove_cvref_t<J>>::deserialize(j, f) };
98} || requires(std::remove_cvref_t<J> const& j) {
99 { Serializer<std::remove_cvref_t<T>, std::remove_cvref_t<J>>::deserialize(j) };
100} || requires(std::remove_cvref_t<J> const& j, F const& f) {
101 { Serializer<std::remove_cvref_t<T>>::deserialize(j, f) };
102} || requires(std::remove_cvref_t<J> const& j) {
103 { Serializer<std::remove_cvref_t<T>>::deserialize(j) };
104} || requires(std::remove_cvref_t<J> const& j, F const& f) {
105 { Serializer<std::remove_cvref_t<T>>::template deserialize<std::remove_cvref_t<J>>(j, f) };
106} || requires(std::remove_cvref_t<J> const& j) {
107 { Serializer<std::remove_cvref_t<T>>::template deserialize<std::remove_cvref_t<J>>(j) };
108};
109
110template <typename T, typename J, typename F>
111constexpr bool has_inplace_deserializer_v = requires(std::remove_cvref_t<T>& t, J&& j, F const& f) {
112 {
113 Serializer<std::remove_cvref_t<T>, std::remove_cvref_t<J>>::deserialize(t, std::forward<J>(j), f)
114 } -> std::convertible_to<ll::Expected<>>;
115} || requires(std::remove_cvref_t<T>& t, J&& j) {
116 {
117 Serializer<std::remove_cvref_t<T>, std::remove_cvref_t<J>>::deserialize(t, std::forward<J>(j))
118 } -> std::convertible_to<ll::Expected<>>;
119} || requires(std::remove_cvref_t<T>& t, J&& j, F const& f) {
120 {
121 Serializer<std::remove_cvref_t<T>>::deserialize(t, std::forward<J>(j), f)
122 } -> std::convertible_to<ll::Expected<>>;
123} || requires(std::remove_cvref_t<T>& t, J&& j) {
124 { Serializer<std::remove_cvref_t<T>>::deserialize(t, std::forward<J>(j)) } -> std::convertible_to<ll::Expected<>>;
125} || requires(std::remove_cvref_t<T>& t, J&& j, F const& f) {
126 {
127 Serializer<std::remove_cvref_t<T>>::template deserialize<std::remove_cvref_t<J>>(t, std::forward<J>(j), f)
128 } -> std::convertible_to<ll::Expected<>>;
129} || requires(std::remove_cvref_t<T>& t, J&& j) {
130 {
131 Serializer<std::remove_cvref_t<T>>::template deserialize<std::remove_cvref_t<J>>(t, std::forward<J>(j))
132 } -> std::convertible_to<ll::Expected<>>;
133};
134
135constexpr std::string_view trim_ascii_spaces(std::string_view sv) {
136 while (!sv.empty() && std::isspace(static_cast<unsigned char>(sv.front()))) {
137 sv.remove_prefix(1);
138 }
139 while (!sv.empty() && std::isspace(static_cast<unsigned char>(sv.back()))) {
140 sv.remove_suffix(1);
141 }
142 return sv;
143}
144
145template <typename Enum, typename F>
146 requires(is_key_formatter_v<std::remove_cvref_t<F>>)
147constexpr std::optional<std::string> enum_name_to_string(Enum value, F const& keyFormatter) {
148 using enum_type = std::remove_cvref_t<Enum>;
149
150 if constexpr (!magic_enum::detail::supported<enum_type>::value) {
151 return std::nullopt;
152 } else if constexpr (magic_enum::detail::subtype_v<enum_type> == magic_enum::detail::enum_subtype::flags) {
153 if (auto const name = magic_enum::enum_flags_name<enum_type>(value); !name.empty()) {
154 if constexpr (has_typed_key_formatter_v<enum_type, F>) {
155 std::string result;
156 size_t cursor{0};
157 auto nameSv = std::string_view{name};
158
159 while (cursor < nameSv.size()) {
160 auto next = nameSv.find('|', cursor);
161 auto part = trim_ascii_spaces(
162 nameSv.substr(cursor, next == std::string_view::npos ? nameSv.size() - cursor : next - cursor)
163 );
164
165 auto partValue = [&]() -> std::optional<enum_type> {
166 if (auto parsed = magic_enum::enum_cast<enum_type>(part)) return *parsed;
167 if (auto parsed = magic_enum::enum_flags_cast<enum_type>(part)) return *parsed;
168 return std::nullopt;
169 }();
170 if (!partValue) return std::string{name};
171
172 if (!result.empty()) result += '|';
173 result += std::string{keyFormatter.template operator()<enum_type>(*partValue)};
174
175 if (next == std::string_view::npos) break;
176 cursor = next + 1;
177 }
178
179 return result;
180 } else {
181 return std::string{name};
182 }
183 }
184 } else {
185 if (auto name = magic_enum::enum_name<enum_type>(value); !name.empty()) {
186 if constexpr (has_typed_key_formatter_v<enum_type, F>) {
187 return std::string{keyFormatter.template operator()<enum_type>(value)};
188 } else {
189 return std::string{name};
190 }
191 }
192 }
193
194 return std::nullopt;
195}
196
197template <typename Enum, typename F>
198 requires(is_key_formatter_v<std::remove_cvref_t<F>>)
199constexpr std::optional<Enum> string_to_enum(std::string_view sv, F const& keyFormatter) {
200 using enum_type = std::remove_cvref_t<Enum>;
201 using underlying_type = std::underlying_type_t<enum_type>;
202
203 if (auto val = magic_enum::enum_cast<enum_type>(sv)) {
204 return *val;
205 }
206 if (auto val = magic_enum::enum_flags_cast<enum_type>(sv)) {
207 return *val;
208 }
209
210 if constexpr (magic_enum::detail::supported<enum_type>::value && has_typed_key_formatter_v<enum_type, F>) {
211 if constexpr (magic_enum::detail::subtype_v<enum_type> == magic_enum::detail::enum_subtype::flags) {
212 underlying_type result{};
213 bool matchedAny = false;
214 size_t cursor = 0;
215
216 while (cursor < sv.size()) {
217 auto const next = sv.find('|', cursor);
218 auto const token = trim_ascii_spaces(
219 sv.substr(cursor, next == std::string_view::npos ? sv.size() - cursor : next - cursor)
220 );
221
222 bool matched = false;
223 for (auto const value : magic_enum::enum_values<enum_type>()) {
224 auto const formatted = enum_name_to_string(value, keyFormatter);
225 if (formatted && *formatted == token) {
226 result |= static_cast<underlying_type>(value);
227 matchedAny = true;
228 matched = true;
229 break;
230 }
231 }
232 if (!matched) {
233 matchedAny = false;
234 break;
235 }
236 if (next == std::string_view::npos) {
237 break;
238 }
239 cursor = next + 1;
240 }
241
242 if (matchedAny) {
243 return static_cast<enum_type>(result);
244 }
245 } else {
246 for (auto const value : magic_enum::enum_values<enum_type>()) {
247 auto const formatted = enum_name_to_string(value, keyFormatter);
248 if (formatted && *formatted == sv) {
249 return value;
250 }
251 }
252 }
253 }
254
255 if (auto num = string_utils::svtonum<underlying_type>(sv)) {
256 return static_cast<enum_type>(*num);
257 }
258
259 return std::nullopt;
260}
261
262} // namespace detail
263
264template <typename F>
265concept IsKeyFormatter = detail::is_key_formatter_v<std::remove_cvref_t<F>>;
266
267template <typename T>
268concept IsLeastStringifiableType = detail::is_key_stringifiable_v<std::remove_cvref_t<T>>;
269
270template <class T>
271constexpr auto const member_name_array_v = boost::pfr::names_as_array<std::remove_cvref_t<T>>();
272
273template <class T>
274constexpr auto const member_count_v = boost::pfr::tuple_size_v<T>;
275
276template <size_t I, class T>
277using member_t = typename boost::pfr::tuple_element_t<I, T>;
278
279template <class T>
281 template <size_t S, size_t A>
283 alignas(A) char storage[S];
284 };
285 template <class... Ts>
286 using AlignedTuple = boost::pfr::detail::sequence_tuple::tuple<AlignedStorage<sizeof(Ts), alignof(Ts)>...>;
287
288 template <size_t I, size_t... Ns>
289 static ptrdiff_t offset(std::index_sequence<Ns...>) noexcept {
290 AlignedTuple<member_t<Ns, T>...> layout{};
291 return static_cast<char const*>(&get<I>(layout).storage[0])
292 - static_cast<char const*>(&get<0>(layout).storage[0]);
293 }
294};
295
296template <size_t I, class T>
297inline auto const member_offset_v = OffsetGetter<T>::template offset<I>(std::make_index_sequence<member_count_v<T>>());
298
299template <Reflectable T, class F>
300constexpr void forEachMember(T&& value, F&& func) {
301 boost::pfr::for_each_field(std::forward<T>(value), [func = std::forward<F>(func)](auto&& field, std::size_t idx) {
302 func(member_name_array_v<T>[idx], std::forward<decltype(field)>(field));
303 });
304}
305
306template <typename T, IsKeyFormatter F>
307constexpr std::string type_to_string(T const& t, F const& keyFormatter) {
308 static_assert(
309 detail::has_custom_key_serializer_v<T, F> || detail::has_typed_key_formatter_v<T, F>
310 || detail::is_string_serializable_v<T> || traits::is_string_convertible_v<T> || std::is_enum_v<T>,
311 "the key type has to be a string, an enum, or a type with a ll::reflection::Serializer<T>::to_string "
312 "specialization"
313 );
314 if constexpr (std::is_enum_v<T>) {
315 if (auto name = detail::enum_name_to_string(t, keyFormatter)) return *std::move(name);
316 if constexpr (detail::has_typed_key_formatter_v<T, F>) {
317 return keyFormatter.template operator()<std::remove_cvref_t<T>>(t);
318 }
319 return std::to_string(fmt::underlying(t));
320 } else if constexpr (detail::has_typed_key_formatter_v<T, F>) {
321 return keyFormatter.template operator()<std::remove_cvref_t<T>>(t);
322 } else if constexpr (detail::has_custom_key_serializer_v<T, F>) {
323 if constexpr (requires { Serializer<T>::to_string(t, keyFormatter); }) {
324 return Serializer<T>::to_string(t, keyFormatter);
325 } else {
326 return Serializer<T>::to_string(t);
327 }
328 } else if constexpr (traits::is_string_convertible_v<T>) {
329 return std::string{t};
330 } else if constexpr (detail::is_string_serializable_v<T>) {
331 return Serializer<T>::to_string(t);
332 } else {
333 static_assert(traits::always_false<T>, "the key type cannot be converted to a string; see the assertion above");
334 }
335}
336
337template <IsLeastStringifiableType T>
338constexpr std::string type_to_string(T const& t) {
339 return type_to_string(t, detail::default_key_formatter);
340}
341
342template <IsLeastStringifiableType T, IsKeyFormatter F>
343constexpr std::optional<T> string_to_type(std::string_view sv, F const& keyFormatter) {
344 using RT = std::remove_cvref_t<T>;
345 if constexpr (detail::has_custom_key_deserializer_v<T, F>) {
346 if constexpr (requires { Serializer<RT>::from_string(sv, keyFormatter); }) {
347 if (auto res = Serializer<RT>::from_string(sv, keyFormatter); res) {
348 return *std::move(res);
349 }
350 } else {
351 if (auto res = Serializer<RT>::from_string(sv); res) {
352 return *std::move(res);
353 }
354 }
355 return std::nullopt;
356 } else if constexpr (detail::is_string_serializable_v<T>) {
357 if (auto res = Serializer<RT>::from_string(sv); res) {
358 return *std::move(res);
359 }
360 return std::nullopt;
361 } else if constexpr (traits::is_string_convertible_v<T>) {
362 return RT{sv};
363 } else {
364 return detail::string_to_enum<RT>(sv, keyFormatter);
365 }
366}
367
368template <IsLeastStringifiableType T>
369constexpr std::optional<T> string_to_type(std::string_view sv) {
370 return string_to_type<T>(sv, detail::default_key_formatter);
371}
372
373} // namespace ll::reflection
Definition Reflection.h:265
Definition Reflection.h:268
Definition Reflection.h:33
Definition Reflection.h:280
Definition Serializer.h:9