welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
annotations.hpp
Go to the documentation of this file.
1#pragma once
2#include <welder/diag.hpp>
3#include <welder/lang.hpp>
4
17
18namespace welder::inline v0 {
19
24using size_type = decltype(sizeof(0));
25
26// The language identity scheme (lang.hpp: welder-shipped 0–15, user_lang
27// 16–31) assumes the mask below spans 32 bits.
28static_assert(sizeof(unsigned) >= 4,
29 "welder's language mask needs a >= 32-bit unsigned");
30
41consteval unsigned lang_bit(lang l) {
42 if (static_cast<unsigned>(l) >= 8 * sizeof(unsigned))
44 return 1u << static_cast<unsigned>(l);
45}
46
55template <class... Ls>
56consteval unsigned lang_mask(Ls... ls) {
57 return (0u | ... | lang_bit(ls));
58}
59
61enum class policy_kind : unsigned char {
62 automatic,
63 opt_in,
64};
65
70enum class accessor_role : unsigned char {
73};
74
90enum class rv_kind : unsigned char {
91 automatic,
92 automatic_reference,
93 take_ownership,
94 copy,
95 move,
96 reference,
97 reference_internal,
98 none,
99};
100
108namespace detail {
109
110// --- weld: the type-level annotation declaring target languages -------------
111
125struct weld_spec {
126 unsigned mask = 0;
127
132 template <class... Ls>
133 consteval weld_spec operator()(Ls... ls) const {
134 return weld_spec{lang_mask(ls...)};
135 }
136};
137
138// --- policy: how greedily members are reflected -----------------------------
139
144
161 unsigned mask = 0;
162
167 template <class... Ls>
168 consteval weld_protected_spec operator()(Ls... ls) const {
169 return weld_protected_spec{lang_mask(ls...)};
170 }
171};
172
173// --- mark: member-level include/exclude -------------------------------------
174
185 unsigned mask = 0;
186
191 template <class... Ls>
192 consteval exclude_spec operator()(Ls... ls) const {
193 return exclude_spec{lang_mask(ls...)};
194 }
195};
196
203 unsigned mask = 0;
204
209 template <class... Ls>
210 consteval include_spec operator()(Ls... ls) const {
211 return include_spec{lang_mask(ls...)};
212 }
213};
214
232struct only_spec {
233 unsigned mask = 0;
234
240 template <class... Ls>
241 consteval only_spec operator()(lang first, Ls... rest) const {
242 return only_spec{lang_mask(first, rest...)};
243 }
244};
245
246// --- no_reassign: force a data member's read-only binding -------------------
247
275 unsigned mask = 0;
276
281 template <class... Ls>
282 consteval no_reassign_spec operator()(Ls... ls) const {
283 return no_reassign_spec{lang_mask(ls...)};
284 }
285};
286
287// --- trust_bindable: vouch that a type is representable outside welder's view --
288
304 unsigned mask = 0;
305
310 template <class... Ls>
311 consteval trust_bindable_spec operator()(Ls... ls) const {
312 return trust_bindable_spec{lang_mask(ls...)};
313 }
314};
315
316// --- getter / setter: method-backed properties -------------------------------
317
329
330// The `getter(langs…[, "name"])` argument list is a run of `lang` markers
331// optionally followed by an explicit property name — the weld_as argument
332// grammar, with the trailing string optional (absent = derive the name from the
333// function's identifier). Two pack-walkers mirror weld_as_mask / weld_as_name:
334// one ORs the leading markers, one copies the trailing name (or leaves the
335// buffer empty). No std headers, keeping the vocabulary module-safe.
336
339consteval unsigned accessor_mask() { return 0u; }
340template <size_type N>
341consteval unsigned accessor_mask(const char (&)[N]) { return 0u; }
342template <class... Rest>
343consteval unsigned accessor_mask(lang l, Rest&&... rest) {
344 return lang_bit(l) | accessor_mask(static_cast<Rest&&>(rest)...);
345}
346
351consteval void accessor_name(char (&)[accessor_name_capacity]) {}
352template <size_type N>
353consteval void accessor_name(char (&dst)[accessor_name_capacity],
354 const char (&s)[N]) {
357 for (size_type i{0}; i < N; ++i)
358 dst[i] = s[i];
359}
360template <class... Rest>
361consteval void accessor_name(char (&dst)[accessor_name_capacity], lang,
362 Rest&&... rest) {
363 accessor_name(dst, static_cast<Rest&&>(rest)...);
364}
365
387 unsigned mask = 0;
389
394 template <class... Args>
395 consteval accessor_spec operator()(Args&&... args) const {
396 accessor_spec s{role, accessor_mask(static_cast<Args&&>(args)...), {}};
397 accessor_name(s.name, static_cast<Args&&>(args)...);
398 return s;
399 }
400};
401
402// --- doc: human-readable documentation --------------------------------------
403
413template <size_type N>
415 char data[N]{};
417 consteval fixed_string(const char (&s)[N]) {
418 for (size_type i{0}; i < N; ++i)
419 data[i] = s[i];
420 }
421};
422
427template <size_type N>
431
440template <size_type N>
444
465template <size_type N, size_type M>
470
471// --- weld_as: force an entity's target-language name verbatim ----------------
472
492template <size_type N>
494 unsigned mask = 0;
496};
497
498// --- return_policy: how a returned object is owned/converted ------------------
499
512
513// --- keep_alive: tie one argument's/return's lifetime to another's -----------
514
529 unsigned nurse = 0;
530 unsigned patient = 0;
531};
532
533} // namespace detail
534
535// --- weld: the type-level annotation declaring target languages -------------
536
552inline constexpr detail::weld_spec weld{};
553
554// --- policy: how greedily members are reflected -----------------------------
555
560namespace policy {
563
573} // namespace policy
574
575// --- mark: member-level include/exclude / trust_bindable --------------------
576
589template <class T>
590inline constexpr bool trust_bindable = false;
591
593namespace mark {
594inline constexpr detail::exclude_spec exclude{};
595inline constexpr detail::include_spec include{};
596inline constexpr detail::only_spec only{};
599} // namespace mark
600
601// --- getter / setter: method-backed properties -------------------------------
602
619
625
626// --- doc: human-readable documentation --------------------------------------
627
640template <size_type N>
641consteval detail::doc_spec<N> doc(const char (&s)[N]) {
643}
644
653template <size_type N>
657
668template <size_type N, size_type M>
669consteval detail::tparam_spec<N, M> tparam(const char (&name)[N], const char (&text)[M]) {
671}
672
673// --- weld_as: force an entity's target-language name verbatim ----------------
674
686template <size_type N>
687consteval detail::weld_as_spec<N> weld_as(const char (&s)[N]) {
689}
690
691namespace detail {
692// The `weld_as(langs…, "name")` argument list is a run of `lang` markers followed
693// by the verbatim name. A parameter pack cannot precede a deduced trailing string
694// (the pack would not deduce), so `weld_as` takes one forwarding pack and these two
695// helpers walk it: one ORs the leading markers, the other peels down to the name —
696// binding the string by reference so its extent N survives (a by-value array decays
697// to a pointer and loses its length). No std headers, so the vocabulary stays
698// module-exportable.
699
702consteval unsigned weld_as_mask() { return 0u; }
703template <size_type N>
704consteval unsigned weld_as_mask(const char (&)[N]) { return 0u; }
705template <class... Rest>
706consteval unsigned weld_as_mask(lang l, Rest&&... rest) {
707 return lang_bit(l) | weld_as_mask(static_cast<Rest&&>(rest)...);
708}
709
712template <size_type N>
713consteval fixed_string<N> weld_as_name(const char (&s)[N]) { return fixed_string<N>{s}; }
714template <class... Rest>
715consteval auto weld_as_name(lang, Rest&&... rest) {
716 return weld_as_name(static_cast<Rest&&>(rest)...);
717}
718} // namespace detail
719
735template <class... Args>
736consteval auto weld_as(Args&&... args) {
737 return detail::weld_as_spec{detail::weld_as_mask(static_cast<Args&&>(args)...),
738 detail::weld_as_name(static_cast<Args&&>(args)...)};
739}
740
741// --- return_policy: how a returned object is owned/converted ------------------
742
760
761namespace detail {
762// The `return_policy(langs…, kind)` argument list is a run of `lang` markers
763// followed by the trailing @ref rv_kind — mirroring `weld_as(langs…, "name")`.
764// Two helpers walk the forwarding pack: one ORs the leading markers, the other
765// peels down to the kind. No std headers, keeping the vocabulary module-safe.
766
769consteval unsigned return_policy_mask(rv_kind) { return 0u; }
770template <class... Rest>
771consteval unsigned return_policy_mask(lang l, Rest... rest) {
772 return lang_bit(l) | return_policy_mask(rest...);
773}
774
777consteval rv_kind return_policy_kind(rv_kind k) { return k; }
778template <class... Rest>
779consteval rv_kind return_policy_kind(lang, Rest... rest) {
780 return return_policy_kind(rest...);
781}
782} // namespace detail
783
801template <class... Args>
806
807// --- keep_alive: tie one argument's/return's lifetime to another's -----------
808
822consteval detail::keep_alive_spec keep_alive(unsigned nurse, unsigned patient) {
823 return detail::keep_alive_spec{nurse, patient};
824}
825
826} // namespace welder
welder's consteval diagnostics, collected in one place: every hand-rolled compile-time error the libr...
Target-language vocabulary — the set of languages welder can bind to.
The stored forms of the annotation vocabulary.
consteval void accessor_name(char(&)[accessor_name_capacity])
Copy an accessor argument list's trailing explicit name into dst (left empty when the list carries no...
consteval unsigned weld_as_mask()
The language mask of a weld_as argument list: the OR of its leading lang markers (the trailing name c...
consteval unsigned return_policy_mask(rv_kind)
The language mask of a return_policy argument list: the OR of its leading lang markers (the trailing ...
consteval fixed_string< N > weld_as_name(const char(&s)[N])
The verbatim name of a weld_as argument list: the trailing string, reached by dropping the leading la...
constexpr size_type accessor_name_capacity
The inline capacity of an accessor's explicit property name.
consteval unsigned accessor_mask()
The language mask of an accessor argument list: the OR of its leading lang markers (a trailing name c...
consteval rv_kind return_policy_kind(rv_kind k)
The policy of a return_policy argument list: the trailing kind, reached by dropping the leading lang ...
The bare mark annotation objects — use directly or call to scope by language.
constexpr detail::trust_bindable_spec trust_bindable
constexpr detail::no_reassign_spec no_reassign
constexpr detail::only_spec only
constexpr detail::exclude_spec exclude
constexpr detail::include_spec include
The policy annotation values.
constexpr detail::weld_protected_spec weld_protected
Admit the type's protected members into resolution — bare (all languages) or called with languages to...
constexpr detail::policy_spec opt_in
constexpr detail::policy_spec automatic
The return-value policy values, the user-facing spelling of rv_kind.
constexpr rv_kind reference
constexpr rv_kind move
constexpr rv_kind reference_internal
constexpr rv_kind automatic_reference
constexpr rv_kind automatic
constexpr rv_kind none
constexpr rv_kind take_ownership
constexpr rv_kind copy
constexpr detail::weld_spec weld
The weld annotation: declare an entity bound, and for which languages.
consteval detail::return_doc_spec< N > returns(const char(&s)[N])
Document a function's return value.
constexpr detail::accessor_spec getter
Mark a member function as a property getter (const, no parameters).
consteval detail::doc_spec< N > doc(const char(&s)[N])
Attach a docstring to a namespace, class, function, or function parameter.
policy_kind
How greedily a type's members are reflected for binding.
@ automatic
Reflect every member unless explicitly excluded (default).
@ opt_in
Reflect only members explicitly marked include.
consteval detail::weld_as_spec< N > weld_as(const char(&s)[N])
Force s as the target name in every welded language.
constexpr detail::accessor_spec setter
Mark a member function as a property setter (exactly one parameter) — the write half of welder::gette...
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...
@ copy
Copy the returned object into a target-owned value.
@ automatic_reference
Like automatic but never take ownership (used for arguments).
@ automatic
The rod default — emit no explicit policy.
@ none
Do not convert (nanobind rv_policy::none); pybind11 has no equivalent.
@ move
Move the returned object into a target-owned value.
@ take_ownership
The target owns the returned pointer and frees it.
@ 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 detail::tparam_spec< N, M > tparam(const char(&name)[N], const char(&text)[M])
Document a template parameter (repeatable, ordered).
consteval unsigned lang_mask(Ls... ls)
The mask naming the languages ls.
consteval detail::return_policy_spec return_policy(Args... args)
Force a return-value policy on a callable, optionally scoped to one or more languages.
constexpr bool trust_bindable
The type-level trust customization point: specialize to true to trust T wherever it appears (member,...
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 detail::keep_alive_spec keep_alive(unsigned nurse, unsigned patient)
Keep the call entity patient alive at least until nurse is collected.
decltype(sizeof(0)) size_type
std::size_t named without a standard-library include, keeping this vocabulary header std-free (see th...
The stored form of a getter / setter mark: which property half the function supplies,...
consteval accessor_spec operator()(Args &&... args) const
Scope the mark by language and/or force an explicit property name.
unsigned mask
The languages it applies to; 0 == all.
char name[accessor_name_capacity]
The explicit property name; empty == derive.
accessor_role role
Which half this function supplies.
The stored form of a doc annotation: a summary docstring.
fixed_string< N > text
The docstring text.
The stored form of an exclude mark: the languages a member is hidden from.
unsigned mask
The languages to exclude from; 0 == all languages.
consteval exclude_spec operator()(Ls... ls) const
Scope the exclusion to specific languages.
A string literal captured by value, length included, so it can live in a structural annotation consta...
consteval fixed_string(const char(&s)[N])
Capture the characters of s.
char data[N]
The captured characters, including the terminator.
The stored form of an include mark: the languages a member is opted into.
consteval include_spec operator()(Ls... ls) const
Scope the inclusion to specific languages.
unsigned mask
The languages to include for; 0 == all languages.
The stored form of a keep_alive annotation: a lifetime dependency between two of a call's entities,...
unsigned patient
The dependant kept alive until the nurse is collected (e.g.
unsigned nurse
The keeper whose collection bounds the dependency (e.g.
The stored form of a no_reassign mark: the languages a data member is bound read-only** for,...
unsigned mask
The languages to bind read-only for; 0 == all languages.
consteval no_reassign_spec operator()(Ls... ls) const
Scope the read-only binding to specific languages.
The stored form of an only mark: the complete set of languages a member may bind for — implicitly,...
unsigned mask
The only languages to bind for; 0 == the (diagnosed) bare form.
consteval only_spec operator()(lang first, Ls... rest) const
Name the complete set of languages the member may bind for.
The stored form of a policy annotation.
policy_kind kind
The chosen policy.
The stored form of a returns annotation: a function's return-value doc.
fixed_string< N > text
The return-value documentation.
The stored form of a return_policy annotation: a return-value policy, optionally scoped to some langu...
unsigned mask
The languages to apply to; 0 == all languages.
rv_kind kind
The chosen policy.
The stored form of a tparam annotation: one template parameter's doc.
fixed_string< N > name
The documented template parameter's name.
fixed_string< M > text
Its documentation.
The stored form of a trust_bindable member mark.
unsigned mask
The languages to trust for; 0 == all languages.
consteval trust_bindable_spec operator()(Ls... ls) const
Scope the vouch to specific languages.
The stored form of a weld_as annotation: a forced target-language name.
unsigned mask
The languages to rename for; 0 == all languages.
fixed_string< N > name
The verbatim target-language name.
The stored form of a policy::weld_protected annotation: the languages a type's protected members are ...
consteval weld_protected_spec operator()(Ls... ls) const
Scope the admission to specific languages.
unsigned mask
The languages to admit protected members for; 0 == all.
The stored form of a weld annotation: the mask of target languages.
unsigned mask
The languages this entity is welded for; 0 == all.
consteval weld_spec operator()(Ls... ls) const
Scope the weld to specific languages.
Thrown by the accessor_name factory helper (<welder/annotations.hpp>) when a getter/setter explicit p...
Definition diag.hpp:104
Thrown by lang_bit (<welder/annotations.hpp>) when a lang value lies past the 32-bit language-mask wi...
Definition diag.hpp:30