77#include <string_view>
88#include <vector>
99
10- template <typename T>
11- struct callable_from;
12-
13- namespace _chroma_impl {
10+ namespace chroma {
11+ namespace _chroma_util {
1412template <char const* V>
1513struct error {
1614 constexpr static auto cond = V == nullptr;
@@ -26,6 +24,26 @@ consteval void panic(T const& message) {
2624 (void)is_complete_type(compile_error); // force instantiation
2725}
2826
27+ consteval bool is_specialization(std::meta::info type, std::meta::info templ) {
28+ if (not is_type(type)) {
29+ throw "not a type";
30+ }
31+ return has_template_arguments(type) &&
32+ template_of(type) == (is_template(templ) ? templ : template_of(templ));
33+ }
34+
35+ constexpr struct {
36+ template <typename F>
37+ decltype(auto) operator->*(F&& fnc) const {
38+ if constexpr (std::is_void_v<std::invoke_result_t<F>>) {
39+ std::forward<F>(fnc)();
40+ } else {
41+ return std::forward<F>(fnc)();
42+ }
43+ }
44+ } eval_rhs;
45+ } // namespace _chroma_util
46+
2947struct unchecked_context {
3048 template <typename F>
3149 static auto operator()(F&& f) {
@@ -36,23 +54,38 @@ struct unchecked_context {
3654 { return std::forward<F>(f)(std::forward<Ts>(args)...); };
3755 }
3856};
57+ constexpr unchecked_context unchecked{};
3958
4059template <typename... Ts>
4160struct assumed_colors {};
4261
43- consteval bool is_specialization(std::meta::info type, std::meta::info templ) {
44- if (not is_type(type)) {
45- throw "not a type";
46- }
47- return has_template_arguments(type) &&
48- template_of(type) == (is_template(templ) ? templ : template_of(templ));
49- }
62+ template <typename... Ts>
63+ constexpr assumed_colors<Ts...> assume_color{};
5064
51- enum struct Viability { accepted, rejected, ignored };
65+ template <typename T>
66+ struct color {
67+ color(color const&) = delete;
68+ color& operator=(color const&) = delete;
69+ color(color&&) = default;
70+ color& operator=(color&&) = default;
71+ ~color() = default;
5272
53- consteval Viability viability_of(std::meta::info fnc, std::meta::info type) {
54- using enum Viability;
55- if (fnc == std::meta::info()) {
73+ protected:
74+ constexpr color() = default;
75+ friend T;
76+ };
77+
78+ template <typename T>
79+ struct callable_from;
80+
81+ template <typename Color>
82+ concept ignorable = not requires { Color::ignorable; } || Color::ignorable;
83+
84+ enum struct viability { accepted, rejected, ignored };
85+
86+ consteval viability viability_of(std::meta::info fnc, std::meta::info type) {
87+ using enum viability;
88+ if (fnc == std::meta::info() and extract<bool>(substitute(^^chroma::ignorable, {type}))) {
5689 return ignored;
5790 }
5891
@@ -62,58 +95,61 @@ consteval Viability viability_of(std::meta::info fnc, std::meta::info type) {
6295 if (annotation == ^^unchecked_context) {
6396 return ignored;
6497 }
65- if (is_specialization(annotation, ^^assumed_colors) and
98+ if (_chroma_util:: is_specialization(annotation, ^^assumed_colors) and
6699 std::ranges::any_of(template_arguments_of(annotation), is_convertible)) {
67100 return accepted;
68101 }
69102 }
70103
71104 for (auto parameter : parameters_of(fnc) | std::views::transform(std::meta::type_of)) {
72- if (is_specialization(parameter, ^^callable_from) and
105+ if (_chroma_util:: is_specialization(parameter, ^^callable_from) and
73106 is_convertible(template_arguments_of(parameter)[0])) {
74107 return accepted;
75108 }
76109 }
77110 return rejected;
78111}
79- } // namespace _chroma_impl
80-
81- constexpr _chroma_impl::unchecked_context unchecked{};
82112
83- template <typename... Ts>
84- constexpr _chroma_impl::assumed_colors<Ts...> assume_color{};
113+ consteval std::vector<std::meta::info> colors_of(std::meta::info fnc) {
114+ std::vector<std::meta::info> result;
115+ for (auto annotation : annotations_of(fnc) | std::views::transform(std::meta::type_of)) {
116+ if (_chroma_util::is_specialization(annotation, ^^assumed_colors)) {
117+ for (auto arg : template_arguments_of(annotation)) {
118+ result.push_back(arg);
119+ }
120+ }
121+ }
122+ for (auto parameter : parameters_of(fnc) | std::views::transform(std::meta::type_of)) {
123+ if (_chroma_util::is_specialization(parameter, ^^callable_from)) {
124+ result.push_back(template_arguments_of(parameter)[0]);
125+ }
126+ }
127+ return result;
128+ }
85129
86- namespace chroma {
87130template <typename T>
88- struct color {
89- color(color const&) = delete;
90- color& operator=(color const&) = delete;
91- color(color&&) = default;
92- color& operator=(color&&) = default;
131+ struct callable_from : color<T> {
132+ constexpr explicit(false) callable_from(color<T> const&) {}
93133
94- protected:
95- constexpr color() = default;
96- friend T;
97- };
98- } // namespace chroma
134+ constexpr explicit(false) callable_from(unchecked_context const&)
135+ requires ignorable<T>
136+ {}
99137
100- template <typename T>
101- struct callable_from : chroma::color<T> {
102- consteval explicit(false) callable_from(chroma::color<T>) {}
103- consteval explicit(false) callable_from(_chroma_impl::unchecked_context) {}
138+ constexpr explicit(false) callable_from(unchecked_context const&)
139+ requires(not ignorable<T>)
140+ = delete ("unchecked access to unignorable color");
104141
105142 consteval explicit(false)
106143 callable_from(std::meta::access_context ctx = std::meta::access_context::current()) {
107- using enum _chroma_impl::Viability;
108- if (_chroma_impl::viability_of(ctx.scope(), ^^T) == rejected) {
109- _chroma_impl::panic(T::error_message);
144+ if (viability_of(ctx.scope(), ^^T) == viability::rejected) {
145+ _chroma_util::panic(T::error_message);
110146 }
111147 }
112148
113149 template <typename U>
114150 requires std::convertible_to<T, U>
115151 operator callable_from<U>() const {
116- return unchecked ;
152+ return chroma::color<U>{} ;
117153 }
118154
119155 callable_from(callable_from const&) = delete;
@@ -125,13 +161,12 @@ struct callable_from : chroma::color<T> {
125161
126162template <typename T>
127163struct not_callable_from {
128- consteval explicit(false) not_callable_from(_chroma_impl:: unchecked_context) {}
164+ constexpr explicit(false) not_callable_from(unchecked_context) {}
129165
130166 consteval explicit(false)
131167 not_callable_from(std::meta::access_context ctx = std::meta::access_context::current()) {
132- using enum _chroma_impl::Viability;
133- if (_chroma_impl::viability_of(ctx.scope(), ^^T) == accepted) {
134- _chroma_impl::panic(T::error_message);
168+ if (viability_of(ctx.scope(), ^^T) == viability::accepted) {
169+ _chroma_util::panic(T::error_message);
135170 }
136171 }
137172
@@ -141,19 +176,12 @@ struct not_callable_from {
141176 not_callable_from& operator=(not_callable_from&&) = default;
142177 constexpr ~not_callable_from() = default;
143178};
179+ } // namespace chroma
144180
145- namespace _chroma_impl {
146- constexpr struct {
147- template <typename F>
148- decltype(auto) operator->*(F&& fnc) const {
149- if constexpr (std::is_void_v<std::invoke_result_t<F>>) {
150- std::forward<F>(fnc)();
151- } else {
152- return std::forward<F>(fnc)();
153- }
154- }
155- } eval_rhs;
156- } // namespace _chroma_impl
181+ using chroma::assume_color;
182+ using chroma::callable_from;
183+ using chroma::not_callable_from;
184+ using chroma::unchecked;
157185
158- #define $unchecked ::_chroma_impl ::eval_rhs->*[&][[= unchecked]]
159- #define $with(...) ::_chroma_impl ::eval_rhs->*[&][[= assume_color<__VA_ARGS__>]]
186+ #define $unchecked ::chroma::_chroma_util ::eval_rhs->*[&][[= unchecked]]
187+ #define $with(...) ::chroma::_chroma_util ::eval_rhs->*[&][[= assume_color<__VA_ARGS__>]]
0 commit comments