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"
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("."))
23#include "boost/pfr.hpp"
25#include "magic_enum/magic_enum_all.hpp"
27namespace ll::reflection {
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>>;
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>;
43constexpr auto default_key_formatter = [](std::string_view sv) -> std::string_view {
return sv; };
46constexpr bool is_string_serializable_v =
requires(T
const& t, std::string_view sv) {
52constexpr bool is_key_stringifiable_v =
53 is_string_serializable_v<T> || traits::is_string_convertible_v<T> || std::is_enum_v<T>;
55template <
typename T,
typename F>
56constexpr bool has_custom_key_serializer_v =
requires(T
const& t, F
const& f) {
58} ||
requires(T
const& t) {
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>;
67template <
typename T,
typename F>
68constexpr bool has_custom_key_deserializer_v =
requires(std::string_view sv, F
const& f) {
70} ||
requires(std::string_view sv) {
74template <
typename T,
typename J,
typename F>
75constexpr bool has_value_serializer_v =
requires(T
const& t, F
const& f) {
77} ||
requires(T
const& t) {
79} ||
requires(T
const& t, F
const& f) {
81} ||
requires(T
const& t) {
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) {
88} ||
requires(T
const& t, std::remove_cvref_t<J>& j) {
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>;
95template <
typename T,
typename J,
typename F>
96constexpr bool has_value_deserializer_v =
requires(std::remove_cvref_t<J>
const& j, F
const& f) {
98} ||
requires(std::remove_cvref_t<J>
const& j) {
100} ||
requires(std::remove_cvref_t<J>
const& j, F
const& f) {
102} ||
requires(std::remove_cvref_t<J>
const& j) {
104} ||
requires(std::remove_cvref_t<J>
const& j, F
const& f) {
106} ||
requires(std::remove_cvref_t<J>
const& j) {
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) {
114 } -> std::convertible_to<ll::Expected<>>;
115} ||
requires(std::remove_cvref_t<T>& t, J&& j) {
118 } -> std::convertible_to<ll::Expected<>>;
119} ||
requires(std::remove_cvref_t<T>& t, J&& j, F
const& f) {
122 } -> std::convertible_to<ll::Expected<>>;
123} ||
requires(std::remove_cvref_t<T>& t, J&& j) {
125} ||
requires(std::remove_cvref_t<T>& t, J&& j, F
const& f) {
128 } -> std::convertible_to<ll::Expected<>>;
129} ||
requires(std::remove_cvref_t<T>& t, J&& j) {
132 } -> std::convertible_to<ll::Expected<>>;
135constexpr std::string_view trim_ascii_spaces(std::string_view sv) {
136 while (!sv.empty() && std::isspace(
static_cast<unsigned char>(sv.front()))) {
139 while (!sv.empty() && std::isspace(
static_cast<unsigned char>(sv.back()))) {
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>;
150 if constexpr (!magic_enum::detail::supported<enum_type>::value) {
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>) {
157 auto nameSv = std::string_view{name};
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)
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;
170 if (!partValue)
return std::string{name};
172 if (!result.empty()) result +=
'|';
173 result += std::string{keyFormatter.template operator()<enum_type>(*partValue)};
175 if (next == std::string_view::npos)
break;
181 return std::string{name};
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)};
189 return std::string{name};
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>;
203 if (
auto val = magic_enum::enum_cast<enum_type>(sv)) {
206 if (
auto val = magic_enum::enum_flags_cast<enum_type>(sv)) {
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;
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)
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);
236 if (next == std::string_view::npos) {
243 return static_cast<enum_type
>(result);
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) {
255 if (
auto num = string_utils::svtonum<underlying_type>(sv)) {
256 return static_cast<enum_type
>(*num);
271constexpr auto const member_name_array_v = boost::pfr::names_as_array<std::remove_cvref_t<T>>();
274constexpr auto const member_count_v = boost::pfr::tuple_size_v<T>;
276template <
size_t I,
class T>
277using member_t =
typename boost::pfr::tuple_element_t<I, T>;
281 template <
size_t S,
size_t A>
283 alignas(A)
char storage[S];
285 template <
class... Ts>
286 using AlignedTuple = boost::pfr::detail::sequence_tuple::tuple<
AlignedStorage<
sizeof(Ts),
alignof(Ts)>...>;
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]);
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>>());
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));
306template <
typename T, IsKeyFormatter F>
307constexpr std::string type_to_string(T
const& t, F
const& keyFormatter) {
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 "
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);
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>) {
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>) {
333 static_assert(traits::always_false<T>,
"the key type cannot be converted to a string; see the assertion above");
337template <IsLeastStringifiableType T>
338constexpr std::string type_to_string(T
const& t) {
339 return type_to_string(t, detail::default_key_formatter);
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>) {
348 return *std::move(res);
352 return *std::move(res);
356 }
else if constexpr (detail::is_string_serializable_v<T>) {
358 return *std::move(res);
361 }
else if constexpr (traits::is_string_convertible_v<T>) {
364 return detail::string_to_enum<RT>(sv, keyFormatter);
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);
Definition Reflection.h:268
Definition Reflection.h:33
Definition Reflection.h:282
Definition Reflection.h:280
Definition Serializer.h:9