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
81enum class rv_kind : unsigned char {
82 automatic,
83 automatic_reference,
84 take_ownership,
85 copy,
86 move,
87 reference,
88 reference_internal,
89 none,
90};
91
99namespace detail {
100
101// --- weld: the type-level annotation declaring target languages -------------
102
104struct weld_spec {
105 unsigned mask = 0;
106};
107
108// --- policy: how greedily members are reflected -----------------------------
109
114
131 unsigned mask = 0;
132
137 template <class... Ls>
138 consteval weld_protected_spec operator()(Ls... ls) const {
139 return weld_protected_spec{lang_mask(ls...)};
140 }
141};
142
143// --- mark: member-level include/exclude -------------------------------------
144
155 unsigned mask = 0;
156
161 template <class... Ls>
162 consteval exclude_spec operator()(Ls... ls) const {
163 return exclude_spec{lang_mask(ls...)};
164 }
165};
166
173 unsigned mask = 0;
174
179 template <class... Ls>
180 consteval include_spec operator()(Ls... ls) const {
181 return include_spec{lang_mask(ls...)};
182 }
183};
184
202struct only_spec {
203 unsigned mask = 0;
204
210 template <class... Ls>
211 consteval only_spec operator()(lang first, Ls... rest) const {
212 return only_spec{lang_mask(first, rest...)};
213 }
214};
215
216// --- trust_bindable: vouch that a type is representable outside welder's view --
217
233 unsigned mask = 0;
234
239 template <class... Ls>
240 consteval trust_bindable_spec operator()(Ls... ls) const {
241 return trust_bindable_spec{lang_mask(ls...)};
242 }
243};
244
245// --- doc: human-readable documentation --------------------------------------
246
256template <size_type N>
258 char data[N]{};
260 consteval fixed_string(const char (&s)[N]) {
261 for (size_type i{0}; i < N; ++i)
262 data[i] = s[i];
263 }
264};
265
270template <size_type N>
274
283template <size_type N>
287
308template <size_type N, size_type M>
313
314// --- weld_as: force an entity's target-language name verbatim ----------------
315
335template <size_type N>
337 unsigned mask = 0;
339};
340
341// --- return_policy: how a returned object is owned/converted ------------------
342
355
356// --- keep_alive: tie one argument's/return's lifetime to another's -----------
357
372 unsigned nurse = 0;
373 unsigned patient = 0;
374};
375
376} // namespace detail
377
378// --- weld: the type-level annotation declaring target languages -------------
379
388template <class... Ls>
389consteval detail::weld_spec weld(Ls... ls) {
390 return detail::weld_spec{lang_mask(ls...)};
391}
392
393// --- policy: how greedily members are reflected -----------------------------
394
399namespace policy {
402
412} // namespace policy
413
414// --- mark: member-level include/exclude / trust_bindable --------------------
415
428template <class T>
429inline constexpr bool trust_bindable = false;
430
432namespace mark {
433inline constexpr detail::exclude_spec exclude{};
434inline constexpr detail::include_spec include{};
435inline constexpr detail::only_spec only{};
437} // namespace mark
438
439// --- doc: human-readable documentation --------------------------------------
440
453template <size_type N>
454consteval detail::doc_spec<N> doc(const char (&s)[N]) {
456}
457
466template <size_type N>
470
481template <size_type N, size_type M>
482consteval detail::tparam_spec<N, M> tparam(const char (&name)[N], const char (&text)[M]) {
484}
485
486// --- weld_as: force an entity's target-language name verbatim ----------------
487
499template <size_type N>
500consteval detail::weld_as_spec<N> weld_as(const char (&s)[N]) {
502}
503
504namespace detail {
505// The `weld_as(langs…, "name")` argument list is a run of `lang` markers followed
506// by the verbatim name. A parameter pack cannot precede a deduced trailing string
507// (the pack would not deduce), so `weld_as` takes one forwarding pack and these two
508// helpers walk it: one ORs the leading markers, the other peels down to the name —
509// binding the string by reference so its extent N survives (a by-value array decays
510// to a pointer and loses its length). No std headers, so the vocabulary stays
511// module-exportable.
512
515consteval unsigned weld_as_mask() { return 0u; }
516template <size_type N>
517consteval unsigned weld_as_mask(const char (&)[N]) { return 0u; }
518template <class... Rest>
519consteval unsigned weld_as_mask(lang l, Rest&&... rest) {
520 return lang_bit(l) | weld_as_mask(static_cast<Rest&&>(rest)...);
521}
522
525template <size_type N>
526consteval fixed_string<N> weld_as_name(const char (&s)[N]) { return fixed_string<N>{s}; }
527template <class... Rest>
528consteval auto weld_as_name(lang, Rest&&... rest) {
529 return weld_as_name(static_cast<Rest&&>(rest)...);
530}
531} // namespace detail
532
548template <class... Args>
549consteval auto weld_as(Args&&... args) {
550 return detail::weld_as_spec{detail::weld_as_mask(static_cast<Args&&>(args)...),
551 detail::weld_as_name(static_cast<Args&&>(args)...)};
552}
553
554// --- return_policy: how a returned object is owned/converted ------------------
555
573
574namespace detail {
575// The `return_policy(langs…, kind)` argument list is a run of `lang` markers
576// followed by the trailing @ref rv_kind — mirroring `weld_as(langs…, "name")`.
577// Two helpers walk the forwarding pack: one ORs the leading markers, the other
578// peels down to the kind. No std headers, keeping the vocabulary module-safe.
579
582consteval unsigned return_policy_mask(rv_kind) { return 0u; }
583template <class... Rest>
584consteval unsigned return_policy_mask(lang l, Rest... rest) {
585 return lang_bit(l) | return_policy_mask(rest...);
586}
587
590consteval rv_kind return_policy_kind(rv_kind k) { return k; }
591template <class... Rest>
592consteval rv_kind return_policy_kind(lang, Rest... rest) {
593 return return_policy_kind(rest...);
594}
595} // namespace detail
596
614template <class... Args>
619
620// --- keep_alive: tie one argument's/return's lifetime to another's -----------
621
635consteval detail::keep_alive_spec keep_alive(unsigned nurse, unsigned patient) {
636 return detail::keep_alive_spec{nurse, patient};
637}
638
639} // 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 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...
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::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
consteval detail::weld_spec weld(Ls... ls)
Build a weld annotation naming the target languages.
consteval detail::return_doc_spec< N > returns(const char(&s)[N])
Document a function's return value.
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.
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.
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 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 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.
Thrown by lang_bit (<welder/annotations.hpp>) when a lang value lies past the 32-bit language-mask wi...
Definition diag.hpp:30