3#if defined(THREADSCHEDULE_HAS_REFLECTION) && THREADSCHEDULE_HAS_REFLECTION
14namespace threadschedule::reflect
17using info = std::meta::info;
18inline constexpr bool enabled =
true;
21consteval auto fields() -> std::span<info const>
23 static_assert(std::meta::is_class_type(^^T) || std::meta::is_union_type(^^T),
24 "threadschedule::reflect::fields<T>() requires a class or union type");
25 return std::define_static_array(std::meta::nonstatic_data_members_of(^^T, std::meta::access_context::current()));
29consteval auto field_count() -> std::size_t
31 return fields<T>().size();
34template <
typename T, std::
size_t I>
35consteval auto field_info() -> info
37 static_assert(I < field_count<T>(),
"reflection field index out of range");
38 return fields<T>()[I];
42consteval auto field_name() -> std::string_view
44 return std::string_view(std::define_static_string(std::meta::identifier_of(Field)));
47template <
typename T, std::
size_t I>
48consteval auto field_name() -> std::string_view
50 return field_name<field_info<T, I>()>();
54consteval auto type_name() -> std::string_view
56 return std::string_view(std::define_static_string(std::meta::display_string_of(^^T)));
60using field_type_t = [: std::meta::type_of(Field) :];
62template <info Field,
typename T>
63constexpr decltype(
auto) get(T&& obj)
65 return (std::forward<T>(obj).[:Field:]);
68template <info Field,
typename Owner>
69inline constexpr bool is_field_of_v = std::meta::is_same_type(std::meta::parent_of(Field), ^^Owner);
72consteval auto field_names() -> std::span<char const* const>;
77template <info... Fields>
78struct projection_type;
81struct projection_type<Field>
83 using type = field_type_t<Field>;
86template <info First, info Second, info... Rest>
87struct projection_type<First, Second, Rest...>
89 using type = std::tuple<field_type_t<First>, field_type_t<Second>, field_type_t<Rest>...>;
92template <
typename T,
typename F, std::size_t... I>
93constexpr void visit_fields_impl(T&& obj, F&& fn, std::index_sequence<I...>)
95 using object_type = std::remove_cv_t<std::remove_reference_t<T>>;
96 constexpr auto names = field_names<object_type>();
97 (fn(names[I], get<field_info<object_type, I>()>(std::forward<T>(obj))), ...);
100template <
typename T, std::size_t... I>
101consteval auto field_names_impl(std::index_sequence<I...>) -> std::span<char const* const>
103 return std::define_static_array(
104 std::array<
char const*,
sizeof...(I)>{std::define_static_string(std::meta::identifier_of(field_info<T, I>()))...});
108consteval info first_field() noexcept
113template <info Field,
typename Owner>
114consteval void require_field_owner()
116 static_assert(std::meta::is_same_type(std::meta::parent_of(Field), ^^Owner),
117 "Reflection field does not belong to the requested owner type");
123consteval auto field_names() -> std::span<char const* const>
125 return detail::field_names_impl<T>(std::make_index_sequence<field_count<T>()>{});
128template <
typename T,
typename F>
129constexpr void visit_fields(T&& obj, F&& fn)
131 using object_type = std::remove_cv_t<std::remove_reference_t<T>>;
132 detail::visit_fields_impl(std::forward<T>(obj), std::forward<F>(fn),
133 std::make_index_sequence<field_count<object_type>()>{});
136template <info... Fields>
137using projection_t =
typename detail::projection_type<Fields...>::type;
139template <info... Fields,
typename T>
140constexpr auto project_value(T&& obj) -> projection_t<Fields...>
142 static_assert(
sizeof...(Fields) > 0,
"project_value requires at least one field");
143 if constexpr (
sizeof...(Fields) == 1)
145 return get<detail::first_field<Fields...>()>(std::forward<T>(obj));
149 return projection_t<Fields...>{get<Fields>(std::forward<T>(obj))...};
153template <info Field,
typename Owner>
154consteval void require_field_owner()
156 detail::require_field_owner<Field, Owner>();