welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
reflect.hpp
Go to the documentation of this file.
1#pragma once
2#include <meta>
3#include <string> // accessor_explicit_name
4
5#include <welder/diag.hpp>
6
17
18namespace welder::inline v0 {
19
28consteval bool weld_mask_admits(unsigned mask, lang L) {
29 return mask == 0 || (mask & lang_bit(L)) != 0;
30}
31
40consteval bool welded_for(std::meta::info type, lang L) {
41 auto anns{std::meta::annotations_of_with_type(type, ^^detail::weld_spec)};
42 return !anns.empty() &&
43 weld_mask_admits(std::meta::extract<detail::weld_spec>(anns[0]).mask, L);
44}
45
57consteval bool names_template_specialization(std::meta::info mem) {
58 return std::meta::is_type_alias(mem) &&
59 std::meta::is_class_type(std::meta::dealias(mem)) &&
60 std::meta::has_template_arguments(std::meta::dealias(mem));
61}
62
74consteval bool alias_welded_for(std::meta::info mem, lang L) {
75 auto own{std::meta::annotations_of_with_type(mem, ^^detail::weld_spec)};
76 if (!own.empty())
77 return weld_mask_admits(
78 std::meta::extract<detail::weld_spec>(own[0]).mask, L);
79 return welded_for(std::meta::dealias(mem), L);
80}
81
92consteval bool alias_marks_admissible(std::meta::info mem) {
93 for (auto a : std::meta::annotations_of(mem)) {
94 auto t{std::meta::type_of(a)};
100 return false;
101 if (std::meta::has_template_arguments(t)) {
102 auto tmpl{std::meta::template_of(t)};
103 if (tmpl == ^^detail::doc_spec || tmpl == ^^detail::return_doc_spec ||
104 tmpl == ^^detail::tparam_spec)
105 return false;
106 }
107 }
108 return true;
109}
110
124consteval bool member_alias_marks_admissible(std::meta::info mem) {
125 for (auto a : std::meta::annotations_of(mem)) {
126 auto t{std::meta::type_of(a)};
127 if (t == ^^detail::weld_spec || t == ^^detail::policy_spec ||
132 return false;
133 if (std::meta::has_template_arguments(t)) {
134 auto tmpl{std::meta::template_of(t)};
135 if (tmpl == ^^detail::doc_spec || tmpl == ^^detail::return_doc_spec ||
136 tmpl == ^^detail::tparam_spec)
137 return false;
138 }
139 }
140 return true;
141}
142
148consteval policy_kind policy_of(std::meta::info type) {
149 auto anns{std::meta::annotations_of_with_type(type, ^^detail::policy_spec)};
150 return anns.empty() ? policy_kind::automatic
151 : std::meta::extract<detail::policy_spec>(anns[0]).kind;
152}
153
171consteval bool protected_welded(std::meta::info type, lang L) {
172 for (auto a : std::meta::annotations_of_with_type(
174 auto s{std::meta::extract<detail::weld_protected_spec>(a)};
175 if (s.mask == 0 || (s.mask & lang_bit(L)) != 0)
176 return true;
177 }
178 return false;
179}
180
188consteval bool excluded_for(std::meta::info member, lang L) {
189 for (auto a : std::meta::annotations_of_with_type(member, ^^detail::exclude_spec)) {
190 auto s{std::meta::extract<detail::exclude_spec>(a)};
191 if (s.mask == 0 || (s.mask & lang_bit(L)) != 0)
192 return true;
193 }
194 return false;
195}
196
204consteval bool included_for(std::meta::info member, lang L) {
205 for (auto a : std::meta::annotations_of_with_type(member, ^^detail::include_spec)) {
206 auto s{std::meta::extract<detail::include_spec>(a)};
207 if (s.mask == 0 || (s.mask & lang_bit(L)) != 0)
208 return true;
209 }
210 return false;
211}
212
224consteval bool trusted_for(std::meta::info member, lang L) {
225 for (auto a : std::meta::annotations_of_with_type(member, ^^detail::trust_bindable_spec)) {
226 auto s{std::meta::extract<detail::trust_bindable_spec>(a)};
227 if (s.mask == 0 || (s.mask & lang_bit(L)) != 0)
228 return true;
229 }
230 return false;
231}
232
243consteval bool member_no_reassign(std::meta::info member, lang L) {
244 for (auto a : std::meta::annotations_of_with_type(member, ^^detail::no_reassign_spec)) {
245 auto s{std::meta::extract<detail::no_reassign_spec>(a)};
246 if (s.mask == 0 || (s.mask & lang_bit(L)) != 0)
247 return true;
248 }
249 return false;
250}
251
260consteval bool has_no_reassign_mark(std::meta::info entity) {
261 return !std::meta::annotations_of_with_type(entity, ^^detail::no_reassign_spec)
262 .empty();
263}
264
276consteval bool accessor_marked(std::meta::info member, accessor_role role, lang L) {
277 for (auto a : std::meta::annotations_of_with_type(member, ^^detail::accessor_spec)) {
278 auto s{std::meta::extract<detail::accessor_spec>(a)};
279 if (s.role == role && (s.mask == 0 || (s.mask & lang_bit(L)) != 0))
280 return true;
281 }
282 return false;
283}
284
290consteval bool is_accessor_for(std::meta::info member, lang L) {
291 return accessor_marked(member, accessor_role::getter, L) ||
293}
294
300consteval bool has_accessor_mark(std::meta::info member) {
301 return !std::meta::annotations_of_with_type(member, ^^detail::accessor_spec)
302 .empty();
303}
304
314consteval std::string accessor_explicit_name(std::meta::info member,
315 accessor_role role, lang L) {
316 for (auto a : std::meta::annotations_of_with_type(member, ^^detail::accessor_spec)) {
317 auto s{std::meta::extract<detail::accessor_spec>(a)};
318 if (s.role == role && (s.mask == 0 || (s.mask & lang_bit(L)) != 0) &&
319 s.name[0] != '\0')
320 return std::string{s.name};
321 }
322 return {};
323}
324
337consteval rv_kind return_policy_of(std::meta::info fn, lang L) {
338 for (auto a : std::meta::annotations_of_with_type(fn, ^^detail::return_policy_spec)) {
339 auto s{std::meta::extract<detail::return_policy_spec>(a)};
340 if (s.mask == 0 || (s.mask & lang_bit(L)) != 0)
341 return s.kind;
342 }
343 return rv_kind::automatic;
344}
345
360template <std::meta::info Fn, lang L>
361consteval void validate_return_policy() {
362 constexpr rv_kind k{return_policy_of(Fn, L)};
363 if constexpr (k == rv_kind::reference || k == rv_kind::reference_internal) {
364 constexpr std::meta::info rt{std::meta::return_type_of(Fn)};
365 if constexpr (!(std::meta::is_pointer_type(rt) ||
366 std::meta::is_lvalue_reference_type(rt) ||
367 std::meta::is_rvalue_reference_type(rt)))
369 }
370}
371
387consteval bool member_bound(std::meta::info member, lang L, policy_kind pol) {
388 if (excluded_for(member, L))
389 return false;
390 auto onlys{std::meta::annotations_of_with_type(member, ^^detail::only_spec)};
391 if (!onlys.empty()) {
392 unsigned mask{0};
393 for (auto a : onlys) {
394 auto s{std::meta::extract<detail::only_spec>(a)};
395 if (s.mask == 0)
396 throw diag::bare_mark_only{};
397 mask |= s.mask;
398 }
399 return (mask & lang_bit(L)) != 0;
400 }
401 if (pol == policy_kind::automatic)
402 return true;
403 return included_for(member, L) || is_accessor_for(member, L);
404}
405
418consteval std::vector<std::meta::info> public_bases(std::meta::info type) {
419 std::vector<std::meta::info> out;
420 constexpr auto ctx{std::meta::access_context::unchecked()};
421 for (auto b : std::meta::bases_of(type, ctx))
422 if (std::meta::is_public(b))
423 out.push_back(std::meta::type_of(b));
424 return out;
425}
426
427} // namespace welder
welder's consteval diagnostics, collected in one place: every hand-rolled compile-time error the libr...
consteval bool welded_for(std::meta::info type, lang L)
Is type welded for language L — i.e.
Definition reflect.hpp:40
consteval bool is_accessor_for(std::meta::info member, lang L)
Does member supply either property half for language L — i.e.
Definition reflect.hpp:290
consteval bool accessor_marked(std::meta::info member, accessor_role role, lang L)
Does member carry a getter/setter mark of role covering L?
Definition reflect.hpp:276
consteval bool member_no_reassign(std::meta::info member, lang L)
Is data member member bound read-only for L by a no_reassign mark?
Definition reflect.hpp:243
policy_kind
How greedily a type's members are reflected for binding.
@ automatic
Reflect every member unless explicitly excluded (default).
consteval bool member_alias_marks_admissible(std::meta::info mem)
May the annotations on member type-alias mem appear there?
Definition reflect.hpp:124
consteval bool trusted_for(std::meta::info member, lang L)
Does member carry a trust_bindable mark covering language L?
Definition reflect.hpp:224
consteval bool alias_welded_for(std::meta::info mem, lang L)
Is the specialization named by alias mem welded for language L — reading the alias's own weld first,...
Definition reflect.hpp:74
lang
The target languages welder ships rods for — but not the whole value space.
Definition lang.hpp:42
rv_kind
How a bound callable's returned object is owned/converted in the target language — welder's backend-n...
@ automatic
The rod default — emit no explicit policy.
@ reference_internal
A non-owning reference tied to the parent's lifetime (implies keep_alive).
@ reference
A non-owning reference; the caller keeps the C++ object alive.
consteval bool excluded_for(std::meta::info member, lang L)
Does member carry an exclude mark covering language L?
Definition reflect.hpp:188
consteval bool protected_welded(std::meta::info type, lang L)
Does type admit its protected members for language L — i.e.
Definition reflect.hpp:171
consteval void validate_return_policy()
Reject a return_policy on Fn (for language L) that contradicts Fn's return type.
Definition reflect.hpp:361
consteval unsigned lang_bit(lang l)
The single-language bit for l within a language mask.
accessor_role
Which half of a property a marked accessor function supplies.
@ getter
The function reads the property's value (const, no parameters).
@ setter
The function writes it (exactly one parameter).
consteval policy_kind policy_of(std::meta::info type)
The reflection policy declared on type, defaulting to automatic.
Definition reflect.hpp:148
consteval bool alias_marks_admissible(std::meta::info mem)
May the annotations on alias-declaration mem appear there?
Definition reflect.hpp:92
consteval bool member_bound(std::meta::info member, lang L, policy_kind pol)
The core decision a backend asks for each member: does member bind for language L under policy pol?
Definition reflect.hpp:387
consteval bool included_for(std::meta::info member, lang L)
Does member carry an include mark covering language L?
Definition reflect.hpp:204
consteval bool has_accessor_mark(std::meta::info member)
Does member carry any getter/setter mark at all (any role, any language)?
Definition reflect.hpp:300
consteval bool has_no_reassign_mark(std::meta::info entity)
Does entity carry any no_reassign mark at all (any language)?
Definition reflect.hpp:260
consteval bool names_template_specialization(std::meta::info mem)
Is mem a namespace-scope alias naming a class-template specialization — the one way an instantiation ...
Definition reflect.hpp:57
consteval std::string accessor_explicit_name(std::meta::info member, accessor_role role, lang L)
The explicit property name an accessor mark of role forces for L, or "" when the name derives from th...
Definition reflect.hpp:314
consteval bool weld_mask_admits(unsigned mask, lang L)
Does a weld mask admit language L?
Definition reflect.hpp:28
consteval std::vector< std::meta::info > public_bases(std::meta::info type)
The types of the public base classes of type.
Definition reflect.hpp:418
consteval rv_kind return_policy_of(std::meta::info fn, lang L)
The return-value policy declared on callable fn for language L.
Definition reflect.hpp:337
The stored form of a getter / setter mark: which property half the function supplies,...
The stored form of a doc annotation: a summary docstring.
The stored form of an exclude mark: the languages a member is hidden from.
The stored form of an include mark: the languages a member is opted into.
The stored form of a keep_alive annotation: a lifetime dependency between two of a call's entities,...
The stored form of a no_reassign mark: the languages a data member is bound read-only** for,...
The stored form of an only mark: the complete set of languages a member may bind for — implicitly,...
The stored form of a policy annotation.
The stored form of a returns annotation: a function's return-value doc.
The stored form of a return_policy annotation: a return-value policy, optionally scoped to some langu...
The stored form of a tparam annotation: one template parameter's doc.
The stored form of a trust_bindable member mark.
The stored form of a policy::weld_protected annotation: the languages a type's protected members are ...
The stored form of a weld annotation: the mask of target languages.
Thrown by member_bound (<welder/reflect.hpp>) when a member carries a bare [[=welder::mark::only]] — ...
Definition diag.hpp:53
Thrown by validate_return_policy (<welder/reflect.hpp>) — every rod runs it at its per-overload bind ...
Definition diag.hpp:41