@@ -29,7 +29,7 @@ consteval void panic(T const& message) {
2929constexpr struct unchecked_context {
3030 template <typename F>
3131 static auto operator()(F&& f) {
32- return [&]<typename... Ts>[[=unchecked_context{}]](Ts&&... args)
32+ return [&]<typename... Ts>[[= unchecked_context{}]](Ts&&... args)
3333#ifndef __clang__
3434 -> std::invoke_result_t<F, Ts...>
3535#endif
@@ -46,42 +46,93 @@ consteval std::vector<std::meta::info> annotations_of_with_type(std::meta::info
4646using std::meta::annotations_of_with_type;
4747#endif
4848
49+ template <typename... Ts>
50+ struct AssumedColors {};
51+
52+ consteval bool is_viable(std::meta::info fnc, std::meta::info type) {
53+ if (fnc == std::meta::info()) {
54+ return true;
55+ }
56+
57+ auto is_convertible = [&](std::meta::info r) { return is_convertible_type(r, type); };
58+
59+ for (auto annotation : annotations_of(fnc) | std::views::transform(std::meta::type_of)) {
60+ if (annotation == ^^unchecked_context) {
61+ return true;
62+ }
63+ if (is_specialization(annotation, ^^AssumedColors) and
64+ std::ranges::any_of(template_arguments_of(annotation), is_convertible)) {
65+ return true;
66+ }
67+ }
68+
69+ for (auto parameter : parameters_of(fnc) | std::views::transform(std::meta::type_of)) {
70+ if (is_specialization(parameter, template_of(^^callable_from)) and
71+ is_convertible(template_arguments_of(parameter)[0])) {
72+ return true;
73+ }
74+ }
75+ return false;
76+ }
4977} // namespace _chroma_impl
5078
5179using _chroma_impl::unchecked;
5280
81+ template <typename... Ts>
82+ constexpr _chroma_impl::AssumedColors<Ts...> assume_color{};
83+
84+ namespace chroma {
5385template <typename T>
54- struct callable_from {
86+ struct color {
87+ protected:
88+ constexpr color() = default;
89+ friend T;
90+ };
91+ } // namespace chroma
92+
93+ template <typename T>
94+ struct callable_from : chroma::color<T> {
95+ consteval explicit(false) callable_from(chroma::color<T>) {}
5596 consteval explicit(false) callable_from(_chroma_impl::unchecked_context) {}
5697
5798 consteval explicit(false)
5899 callable_from(std::meta::access_context ctx = std::meta::access_context::current()) {
59- bool is_unchecked =
60- ctx.scope() == std::meta::info() or
61- _chroma_impl::annotations_of_with_type(ctx.scope(), ^^_chroma_impl::unchecked_context).size() != 0;
62- auto is_valid = [](std::meta::info type) {
63- return has_template_arguments(type) and
64- (template_of(type) == template_of(^^callable_from)) and
65- std::ranges::any_of(template_arguments_of(type),
66- [](std::meta::info r) { return is_convertible_type(r, ^^T); });
67- };
68- bool constrains_callee =
69- is_function(ctx.scope()) and
70- std::ranges::any_of(parameters_of(ctx.scope()),
71- [&](std::meta::info p) { return is_valid(remove_cvref(type_of(p))); });
72-
73- if (not(is_unchecked or constrains_callee)) {
74- _chroma_impl::panic(T::error_message);
100+ if (not _chroma_impl::is_viable(ctx.scope(), ^^T)) {
101+ panic(T::error_message);
75102 }
76103 }
77104
105+ template <typename U>
106+ requires std::convertible_to<T, U>
107+ operator callable_from<U>() const {
108+ return unchecked;
109+ }
110+
78111 callable_from(callable_from const&) = delete;
79112 callable_from& operator=(callable_from const&) = delete;
80113 callable_from(callable_from&&) = default;
81114 callable_from& operator=(callable_from&&) = default;
82115 constexpr ~callable_from() = default;
83116};
84117
118+ template <typename T>
119+ struct not_callable_from {
120+ consteval explicit(false) not_callable_from(unchecked_context) {}
121+
122+ consteval explicit(false)
123+ not_callable_from(std::meta::access_context ctx = std::meta::access_context::current()) {
124+ if (_chroma_impl::is_viable(ctx.scope(), ^^T)) {
125+ panic(T::error_message);
126+ }
127+ }
128+
129+ not_callable_from(not_callable_from const&) = delete;
130+ not_callable_from& operator=(not_callable_from const&) = delete;
131+ not_callable_from(not_callable_from&&) = default;
132+ not_callable_from& operator=(not_callable_from&&) = default;
133+ constexpr ~not_callable_from() = default;
134+ };
135+
85136namespace _chroma_impl {
86137constexpr struct {
87138 template <typename F>
@@ -94,23 +145,6 @@ constexpr struct {
94145 }
95146} eval_rhs;
96147} // namespace _chroma_impl
97- #define $unchecked ::_chroma_impl::eval_rhs->*[&][[= unchecked]]
98-
99- #define PARENS ()
100-
101- #define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
102- #define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
103- #define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
104- #define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
105- #define EXPAND1(...) __VA_ARGS__
106148
107- #define FOR_EACH(macro, ...) \
108- __VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, __VA_ARGS__)))
109- #define FOR_EACH_HELPER(macro, a1, ...) \
110- macro(a1) __VA_OPT__(, ) \
111- __VA_OPT__(FOR_EACH_AGAIN PARENS(macro, __VA_ARGS__))
112- #define FOR_EACH_AGAIN() FOR_EACH_HELPER
113-
114- #define UNCHECKED_COLOR(name) callable_from<name> = {std::meta::access_context::unchecked()}
115-
116- #define $with(...) ::_chroma_impl::eval_rhs->*[&](FOR_EACH(UNCHECKED_COLOR, __VA_ARGS__))
149+ #define $unchecked ::_chroma_impl::eval_rhs->*[&][[= unchecked]]
150+ #define $with(...) ::_chroma_impl::eval_rhs->*[&][[= assume_color<__VA_ARGS__>]]
0 commit comments