welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
carriage.hpp
Go to the documentation of this file.
1#pragma once
2#include <array>
3#include <cstddef>
4#include <meta>
5#include <type_traits>
6#include <utility>
7
8#include <welder/bind_traits.hpp> // what-binds selection layer
9#include <welder/bindable.hpp> // bindability gate + caster_oracle
10#include <welder/concepts.hpp> // the welder::rod contract
11#include <welder/containers.hpp> // is_reference_container / rod_binds_containers
12#include <welder/doc.hpp> // doc_of (class / namespace docstrings)
13#include <welder/naming.hpp> // naming::none + name_of (weld_as + name styling)
14#include <welder/reflect.hpp> // welded_for / policy_of / member_bound
15
37
38namespace welder::inline v0 {
39
40namespace detail {
41
54template <class Resolution, std::meta::info Ns, std::meta::info Alias>
55consteval bool sole_alias_of_target(lang L, policy_kind pol) {
56 for (auto m :
57 std::meta::members_of(Ns, std::meta::access_context::unchecked())) {
59 continue;
60 // Self-identity by NAME, not by `==`: gcc-16 compares two alias
61 // reflections of the same underlying type as equal, which would make the
62 // duplicate invisible. Two aliases cannot share an identifier in one
63 // namespace, so the identifier is the reliable identity here.
64 if (std::meta::identifier_of(m) == std::meta::identifier_of(Alias))
65 continue;
66 if (std::meta::dealias(m) == std::meta::dealias(Alias) &&
67 Resolution::alias_participates(m, L, pol, Ns))
68 return false;
69 }
70 return true;
71}
72
88template <std::meta::info Alias, lang L, class Style,
90consteval const char* alias_bound_name() {
91 if constexpr (welder::weld_as_of<Alias, L>() != nullptr)
94 nullptr)
95 return welder::weld_as_of<std::meta::dealias(Alias), L>();
96 else
98}
99
100} // namespace detail
101
106consteval bool is_nested_type(std::meta::info type) {
107 const std::meta::info outer{std::meta::parent_of(type)};
108 return std::meta::is_type(outer) && std::meta::is_class_type(outer);
109}
110
111namespace detail {
112
131template <class Resolution>
132consteval bool nested_type_registered(std::meta::info type, lang L) {
133 const std::meta::info outer{std::meta::parent_of(type)};
134 return std::meta::has_identifier(type) && std::meta::is_complete_type(type) &&
136 member_bound(type, L, policy_of(outer)) &&
137 Resolution::counts_as_registered(outer, L);
138}
139
155template <class Resolution, std::meta::info Outer, std::meta::info Alias>
157 for (auto m : std::meta::members_of(Outer,
158 std::meta::access_context::unchecked())) {
159 if (!std::meta::is_type_alias(m) || !std::meta::has_identifier(m))
160 continue;
161 // Self-identity by NAME (== collapses alias reflections on gcc-16; two
162 // member aliases cannot share an identifier in one class).
163 if (std::meta::identifier_of(m) == std::meta::identifier_of(Alias))
164 continue;
165 if (std::meta::dealias(m) == std::meta::dealias(Alias) &&
167 Resolution::class_member_participates(m, L, pol, Outer))
168 return false;
169 }
170 return true;
171}
172
186template <class Resolution>
187consteval bool registered_by_member_alias(std::meta::info scope,
188 std::meta::info type, lang L) {
189 const policy_kind pol{policy_of(scope)};
190 for (auto m : std::meta::members_of(scope,
191 std::meta::access_context::unchecked())) {
192 if (!std::meta::is_type_alias(m) || !std::meta::has_identifier(m))
193 continue;
194 if (std::meta::dealias(m) != type)
195 continue;
196 if (member_access_admitted<Resolution>(m, L, scope) &&
197 Resolution::class_member_participates(m, L, pol, scope))
198 return true;
199 }
200 return false;
201}
202
221template <class Resolution, std::meta::info Scope>
222struct scoped_registration : Resolution {
223 static consteval bool counts_as_registered(std::meta::info type, lang L) {
224 if (Resolution::counts_as_registered(type, L))
225 return true;
226 if (!(std::meta::is_class_type(type) || std::meta::is_enum_type(type)))
227 return false;
228 // The nested chain, alias-aware: a nested type of an alias-registered
229 // target resolves through this oracle again.
230 if (welder::is_nested_type(type) &&
232 return true;
233 return registered_by_member_alias<Resolution>(Scope, type, L);
234 }
235};
236
237} // namespace detail
238
239namespace carriages {
240
241// --- resolution policies ----------------------------------------------------
242//
243// A carriage's *resolution* decides **which** entities participate — the reading of
244// welder's markers — kept separate from *how* they are emitted (the carriage body)
245// and *whether* they are representable (the bindability gate, which both share). Two
246// ship: `marker_resolution` (honor `weld`/`policy`/marks — the default) and
247// `greedy_resolution` (ignore the markers, bind everything — tack welding).
248
257 static consteval bool participates(std::meta::info entity, lang L) {
258 return welder::welded_for(entity, L);
259 }
260
263 static consteval bool is_native_base(std::meta::info base, lang L,
264 std::meta::info /*bound_into*/) {
265 return welder::welded_for(base, L);
266 }
267
268 template <std::meta::info T, lang L>
269 static consteval auto native_bases() {
271 }
272
275 static consteval bool member_participates(std::meta::info mem, lang L,
276 policy_kind pol,
277 std::meta::info /*bound_into*/) {
278 return welder::welded_for(mem, L) && member_bound(mem, L, pol);
279 }
280
284 static consteval bool alias_participates(std::meta::info mem, lang L,
285 policy_kind pol,
286 std::meta::info /*bound_into*/) {
287 return welder::alias_welded_for(mem, L) &&
288 member_bound(std::meta::dealias(mem), L, pol);
289 }
290
297 static consteval bool class_member_participates(std::meta::info mem, lang L,
298 policy_kind pol,
299 std::meta::info /*bound_into*/) {
300 return member_bound(mem, L, pol);
301 }
302
312 static consteval bool protected_participates(std::meta::info mem, lang L,
313 std::meta::info /*bound_into*/) {
314 return welder::protected_welded(std::meta::parent_of(mem), L);
315 }
316
318 static consteval bool namespace_participates(std::meta::info ns, lang L,
319 policy_kind pol,
320 std::meta::info /*bound_into*/) {
321 return member_bound(ns, L, pol) && detail::namespace_has_bound(ns, L);
322 }
323
331 static consteval bool counts_as_registered(std::meta::info type, lang L) {
332 if (welder::welded_for(type, L))
333 return true;
334 if ((std::meta::is_class_type(type) || std::meta::is_enum_type(type)) &&
337 return false;
338 }
339};
340
364template <bool WeldProtected = false>
366 static consteval bool participates(std::meta::info, lang) { return true; }
367 static consteval bool is_native_base(std::meta::info, lang,
368 std::meta::info /*bound_into*/) {
369 return false;
370 }
371 template <std::meta::info, lang>
372 static consteval auto native_bases() {
373 return std::array<std::meta::info, 0>{};
374 }
375 static consteval bool member_participates(std::meta::info mem, lang L,
376 policy_kind pol,
377 std::meta::info /*bound_into*/) {
378 return member_bound(mem, L, pol);
379 }
380
382 static consteval bool alias_participates(std::meta::info mem, lang L,
383 policy_kind pol,
384 std::meta::info /*bound_into*/) {
385 return member_bound(std::meta::dealias(mem), L, pol);
386 }
387
389 static consteval bool class_member_participates(std::meta::info mem, lang L,
390 policy_kind pol,
391 std::meta::info /*bound_into*/) {
392 return member_bound(mem, L, pol);
393 }
394
399 static consteval bool protected_participates(std::meta::info mem, lang L,
400 std::meta::info /*bound_into*/) {
401 return WeldProtected ||
402 welder::protected_welded(std::meta::parent_of(mem), L);
403 }
404 static consteval bool namespace_participates(std::meta::info ns, lang L,
405 policy_kind pol,
406 std::meta::info /*bound_into*/) {
407 return member_bound(ns, L, pol) && detail::namespace_has_bindable(ns, L);
408 }
409
433 static consteval bool counts_as_registered(std::meta::info type, lang L) {
434 if (!(std::meta::is_class_type(type) || std::meta::is_enum_type(type)))
435 return false;
436 if (!std::meta::is_complete_type(type))
437 return false;
438 if (welder::is_nested_type(type))
440 return member_bound(type, L, policy_kind::automatic);
441 }
442};
443
467template <resolution Resolution>
469 private:
489 template <rod B, std::meta::info BoundInto, std::meta::info Src, class Style,
490 class Cls>
491 static void bind_members(Cls& cls) {
492 constexpr lang L{B::language};
493 constexpr auto ctx{std::meta::access_context::unchecked()};
494
495 template for (constexpr auto base :
496 std::define_static_array(welder::public_bases(Src))) {
497 if constexpr (!Resolution::is_native_base(base, L, Src))
499 }
500
501 constexpr policy_kind pol{policy_of(Src)};
502
503 // The gate for class members runs through the SCOPE-AWARE oracle: the
504 // bound-into type's own member aliases register types the plain oracle
505 // cannot see (an alias is unrecoverable from the type it names).
507
508 template for (constexpr auto mem : std::define_static_array(
509 std::meta::nonstatic_data_members_of(Src, ctx))) {
510 // UNNAMED data members — anonymous unions, unnamed bit-fields —
511 // are structurally unbindable (there is nothing to name the
512 // attribute by; an anonymous union also has no declarator to
513 // carry a mark, and unions never bind anyway), so they are
514 // skipped before resolution, like unnamed nested types. The
515 // enclosing type's named members still bind.
516 if constexpr (std::meta::has_identifier(mem) &&
518 BoundInto) &&
519 Resolution::class_member_participates(mem, L, pol,
520 BoundInto)) {
522 B::template add_field<mem, Style>(cls);
523 }
524 }
525
526 // `no_reassign` forces a data member's read-only binding — it shapes an
527 // attribute, so it is meaningless on a method, a constructor, a static
528 // member, or a nested type. Reject it there rather than silently ignore it.
529 // The kind guard runs FIRST so `&&` short-circuits before
530 // has_no_reassign_mark (annotations_of throws on a member template, which
531 // members_of can yield); a nonstatic data member is excluded explicitly.
532 template for (constexpr auto mem :
533 std::define_static_array(std::meta::members_of(Src, ctx))) {
534 static_assert(
535 !((std::meta::is_type(mem) || std::meta::is_function(mem) ||
536 std::meta::is_variable(mem)) &&
537 !std::meta::is_nonstatic_data_member(mem) &&
539 "welder: [[=welder::mark::no_reassign]] applies to a nonstatic data "
540 "member only — it forces that member's read-only binding, which has "
541 "no meaning on a method, constructor, static member, or nested type");
542 }
543
544 // Methods are emitted as whole OVERLOAD GROUPS: the walk fires on each
545 // group's first participating overload (the leader), gathers the
546 // resolution-admitted set, gates every member, and hands the group to
547 // the rod in one call — so one-value-per-name frameworks (the Lua rods)
548 // register a complete set, and per-overload marks / bespoke resolutions
549 // shape the group identically on every rod. (Operators are NOT handled
550 // here: their slot groups span this flattening recursion AND the
551 // anchored free operators of the enclosing namespace, so they are
552 // emitted once per welded type — see bind_operators.)
553 template for (constexpr auto fn :
554 std::define_static_array(std::meta::members_of(Src, ctx))) {
555 // An accessor-marked function (getter/setter covering L) is not a
556 // method here — it binds as a PROPERTY (see bind_properties); for
557 // languages its marks don't cover, it stays an ordinary method.
558 if constexpr (detail::is_method_candidate(fn) &&
559 !welder::is_accessor_for(fn, L) &&
561 BoundInto) &&
562 Resolution::class_member_participates(fn, L, pol,
563 BoundInto)) {
564 if constexpr (detail::is_overload_leader<
566 fn, L, BoundInto)) {
567 constexpr auto grp{detail::overload_group<
569 BoundInto>()};
570 template for (constexpr auto member :
571 std::define_static_array(grp)) {
573 }
574 if constexpr (std::meta::is_static_member(fn))
575 B::template add_static_method<grp, Style>(cls);
576 else
577 B::template add_method<grp, Style>(cls);
578 }
579 }
580 // A member function TEMPLATE falls through every branch: not a
581 // bindable entity (welder cannot invent its template arguments) —
582 // bind an instantiation by chaining it onto the class handle
583 // weld_type returns. A participation mark on one is inert, and NOT
584 // diagnosable: P2996 refuses annotations_of on an uninstantiated
585 // template (the mark is readable only through an instantiation), so
586 // welder cannot even see it here to fail fast.
587 }
588 }
589
597 template <rod B, class E, class Style, class EnumHandle>
598 static void emit_enumerators(EnumHandle& e) {
599 constexpr lang L{B::language};
600 constexpr policy_kind pol{policy_of(^^E)};
601 template for (constexpr auto en :
602 std::define_static_array(std::meta::enumerators_of(^^E))) {
603 if constexpr (Resolution::class_member_participates(en, L, pol, ^^E))
604 B::template add_enumerator<en, Style>(e);
605 }
606 }
607
624 template <rod B, class E, class Style>
625 static std::vector<welder::detail::enumerator_doc> collect_enum_docs() {
626 constexpr lang L{B::language};
627 constexpr policy_kind pol{policy_of(^^E)};
628 std::vector<welder::detail::enumerator_doc> out{};
629 template for (constexpr auto en :
630 std::define_static_array(std::meta::enumerators_of(^^E))) {
631 if constexpr (Resolution::class_member_participates(en, L, pol, ^^E)) {
632 constexpr const char* text{welder::doc_of<en>()};
633 if constexpr (text != nullptr)
634 out.push_back(
635 {welder::name_of<en, L, Style, ent_kind::enumerator>(), text});
636 }
637 }
638 return out;
639 }
640
657 template <rod B, class T, class Style, class Cls>
658 static void bind_class_interior(typename B::module_type& m, Cls& cls) {
659 constexpr lang L{B::language};
660
661 // Nested member types (classes + enums declared inside T) — recursive:
662 // each one's own interior runs this walk again.
664
665 // Constructors, handed to the rod as ONE participating set (several
666 // frameworks want them all at once — sol2's sol::constructors, LuaBridge3's
667 // addConstructor). Three carriage-computed pieces:
668 // - the default constructor: constructibility is decided against the type
669 // welder actually constructs, which may be a rod-nominated substitute —
670 // a Python trampoline standing in for an abstract base — exposed as an
671 // optional `B::construction_type<T>` (fall back to T when a rod names
672 // none); a *declared* default constructor's explicit marks are honored
673 // (default_ctor_admitted);
674 // - each participating public non-copy/move constructor — resolved
675 // SYMMETRICALLY with every other member (the type's policy + the
676 // constructor's own marks, per constructor) — each gated for
677 // bindability;
678 // - for a baseless aggregate whose fields all participate, a synthesized
679 // field constructor;
680 // - the COPY constructor, as a bool only — it never binds as an init
681 // overload; its target-language spelling is the rod's (the Python
682 // rods emit __copy__/__deepcopy__ over it, the Lua rods ignore it).
683 // Marks on a declared copy constructor are honored exactly like the
684 // default constructor's (copy_ctor_admitted). Move constructors
685 // never bind at all — an include/only mark on one is a designed
686 // hard error (validate_move_ctor_marks), not a silent drop.
688 constexpr bool has_default{
689 [] {
690 if constexpr (requires {
691 typename B::template construction_type<T>;
692 })
693 return std::is_default_constructible_v<
694 typename B::template construction_type<T>>;
695 else
696 return std::is_default_constructible_v<T>;
697 }() &&
699 constexpr auto ctors{
701 template for (constexpr auto ctor : std::define_static_array(ctors)) {
702 // Scope-aware gate: T's own member aliases may register a
703 // parameter's type (see bind_members' Reg).
706 }
707 constexpr bool aggregate{
709 // The fail-safe against SILENT uninstantiability: if the policy filtering
710 // left T with no constructor at all, but this same resolution would have
711 // admitted some under `automatic`, the emptiness came from a default (an
712 // opt_in type whose constructors nobody marked) rather than a decision —
713 // hard error. Explicit emptiness passes: mark::exclude-ing the
714 // constructors zeroes the automatic baseline too (factory-only intent),
715 // and a type automatic would also leave bare (private/deleted ctors, an
716 // abstract base) was never instantiable to begin with.
717 static_assert(
718 has_default || aggregate || ctors.size() != 0 ||
719 detail::ctor_group<Resolution, ^^T, L,
721 .size() == 0,
722 "welder: policy filtering left this type with NO constructor — it "
723 "would be silently uninstantiable from the target language. Mark a "
724 "constructor [[=welder::mark::include]] (opt_in binds only marked "
725 "members, constructors included), or mark them all "
726 "[[=welder::mark::exclude]] to make a factory-only surface explicit. "
727 "The type is the T of this bind_type<B, T, Style> instantiation.");
728 constexpr bool copyable{
729 std::is_copy_constructible_v<T> &&
731 // Pass the name style through when the rod's hook takes it (it styles
732 // constructor keyword-argument names); a rod predating the parameter
733 // still binds with its 5-argument form.
734 if constexpr (requires {
735 B::template add_constructors<T, ctors, has_default,
736 aggregate, copyable,
737 Style>(cls);
738 })
739 B::template add_constructors<T, ctors, has_default, aggregate,
740 copyable, Style>(cls);
741 else
742 B::template add_constructors<T, ctors, has_default, aggregate,
743 copyable>(cls);
744
745 // Data members + methods (T's own, plus flattened bases).
747
748 // Method-backed properties (getter/setter marks) — resolved once per
749 // welded type across the same flattening, like the operator slots.
751
752 // Operators — emitted once per welded type, across every source.
754 }
755
769 template <rod B, class T, class Style, class Cls>
770 static void bind_properties(Cls& cls) {
771 constexpr lang L{B::language};
773 template for (constexpr auto p :
774 std::define_static_array(
776 welder::assert_callable_bindable<B, p.getter, L, Reg>();
777 // The setter gates its PARAMETER only: its return value (a fluent
778 // T& chains in C++) is discarded by every rod — the property
779 // protocol has no slot for it — so it never faces the gate.
780 if constexpr (p.setter != std::meta::info{})
782 B::template add_property<T, p.getter, p.setter>(
783 cls, detail::property_bound_name<p.getter, L, Style>());
784 }
785 }
786
812 template <rod B, class T, class Cls>
813 static void bind_operators(Cls& cls) {
814 constexpr lang L{B::language};
816
817 template for (constexpr auto fn :
818 std::define_static_array(
820 if constexpr (std::meta::operator_of(fn) ==
821 std::meta::operators::op_spaceship) {
822 if constexpr (detail::is_overload_leader<
824 ^^T)) {
825 constexpr auto grp{detail::overload_group<
827 template for (constexpr auto member :
828 std::define_static_array(grp)) {
829 welder::assert_operands_bindable<B, member, ^^T, L,
830 Reg>();
831 }
832 B::template add_comparisons<
833 T, grp,
835 cls);
836 }
837 } else if constexpr (B::special_method_name(fn) != nullptr) {
838 if constexpr (detail::is_overload_leader<
840 ^^T)) {
841 constexpr auto grp{detail::overload_group<
843 template for (constexpr auto member :
844 std::define_static_array(grp)) {
846 }
847 B::template add_operator<T, grp>(cls);
848 }
849 }
850 }
851
852 // The stringifier: at most one inserter binds (the to-string protocols
853 // take no second operand to overload on; entry [0] wins, in declaration
854 // order). Only T itself is gated — it is the welded type, so there is
855 // nothing further to assert.
856 constexpr auto strs{std::define_static_array(
858 if constexpr (strs.size() != 0)
859 B::template add_stringifier<T, strs[0]>(cls);
860 }
861
891 template <rod B, std::meta::info Outer, class Style, class Cls>
892 static void bind_nested_types(typename B::module_type& m, Cls& cls) {
893 constexpr lang L{B::language};
894 constexpr auto ctx{std::meta::access_context::unchecked()};
895 constexpr policy_kind pol{policy_of(Outer)};
896 template for (constexpr auto mem : std::define_static_array(
897 std::meta::members_of(Outer, ctx))) {
898 if constexpr (std::meta::is_type(mem) &&
899 !std::meta::is_type_alias(mem) &&
900 (std::meta::is_class_type(mem) ||
901 std::meta::is_enum_type(mem)) &&
902 std::meta::has_identifier(mem) &&
903 std::meta::is_complete_type(mem)) {
905 mem, L, Outer) &&
906 Resolution::class_member_participates(mem, L, pol,
907 Outer)) {
908 if constexpr (std::meta::is_enum_type(mem))
909 bind_nested_enum<B, typename [:mem:], Style>(m, cls);
910 else
912 }
913 } else if constexpr (std::meta::is_type_alias(mem) &&
914 std::meta::has_identifier(mem) &&
915 (std::meta::is_class_type(
916 std::meta::dealias(mem)) ||
917 std::meta::is_enum_type(
918 std::meta::dealias(mem))) &&
919 std::meta::is_complete_type(
920 std::meta::dealias(mem))) {
921 // A MEMBER TYPE ALIAS: participates by the member rules (the
922 // outer's policy + the alias's own marks), with the bindability
923 // gate as the register-or-skip arbiter — a target the gate
924 // already passes (natively castable, a bindable STL wrapper,
925 // welded, otherwise registered, or trusted) converts without
926 // this registration, so registering it again would be redundant
927 // or an outright duplicate. The rule registers exactly the
928 // types that otherwise could not cross the boundary — nested
929 // under the outer, named by the alias (its weld_as → the
930 // target's → the styled identifier). Under greedy resolution
931 // every complete type passes the gate, so member aliases never
932 // participate in a tack weld, by construction.
933 static_assert(
935 "welder: only weld_as / exclude / include / only may be "
936 "attached to a member type alias; policy and doc marks "
937 "belong on the target type, and weld / trust_bindable have "
938 "no meaning here (participation follows the outer's policy "
939 "and the bindability gate)");
941 mem, L, Outer) &&
942 Resolution::class_member_participates(mem, L, pol,
943 Outer) &&
945 B, typename [:std::meta::dealias(mem):], L,
946 Resolution>()) {
947 static_assert(
948 detail::sole_member_alias_of_target<Resolution, Outer,
949 mem>(L, pol),
950 "welder: two member aliases in this class weld the SAME "
951 "target type — each target may be registered under "
952 "exactly one name; mark::exclude one of them");
953 if constexpr (std::meta::is_enum_type(
954 std::meta::dealias(mem)))
955 bind_nested_enum<B, typename [:std::meta::dealias(mem):],
956 Style>(
957 m, cls,
958 detail::alias_bound_name<mem, L, Style,
959 ent_kind::enum_>());
960 else
961 bind_nested_type<B, typename [:std::meta::dealias(mem):],
962 Style, mem>(
964 }
965 }
966 }
967 }
968
996 template <rod B, class T, class Style, std::meta::info Decl = std::meta::info{},
997 class OuterCls>
998 static void bind_nested_type(typename B::module_type& m, OuterCls& outer,
999 const char* name = nullptr) {
1000 constexpr lang L{B::language};
1001 // name_of_or, not `name ? name : name_of<…>`: the consteval fallback
1002 // must only be compiled when T is statically nameable — an alias-welded
1003 // specialization has no identifier and always arrives with an override.
1004 const char* cls_name{
1006 auto cls{make_nested_class_of<B, T, Decl,
1007 Resolution::template native_bases<^^T, L>()>(
1008 m, outer, cls_name, welder::doc_of<^^T>())};
1010 // A second OPTIONAL rod hook, after the interior: a rod whose class
1011 // handle re-opens the class by name/path (LuaBridge3) cannot move the
1012 // class under the outer at creation time — every later add_* call would
1013 // re-open a key that no longer exists — so it finalizes the placement
1014 // here, once the interior (nested types included, so innermost first)
1015 // is fully registered.
1016 if constexpr (requires {
1017 B::template finish_nested_class<T>(m, outer, cls,
1018 cls_name);
1019 })
1020 B::template finish_nested_class<T>(m, outer, cls, cls_name);
1021 }
1022
1034 template <rod B, class E, class Style, class OuterCls>
1035 static void bind_nested_enum(typename B::module_type& m, OuterCls& outer,
1036 const char* name = nullptr) {
1037 constexpr lang L{B::language};
1038 const char* enum_name{
1040 const auto docs{collect_enum_docs<B, E, Style>()};
1042 auto e{make_nested_enum_of<B, E>(m, outer, enum_name, ed)};
1044 B::template finish_enum<E>(e);
1045 }
1046
1066 template <rod B, class T, std::meta::info Decl, auto Bases, class OuterCls>
1067 static auto make_nested_class_of(typename B::module_type& m, OuterCls& outer,
1068 const char* cls_name, const char* doc) {
1069 constexpr std::meta::info decl{Decl == std::meta::info{} ? ^^T : Decl};
1070 if constexpr (requires {
1071 B::template make_nested_class<T, decl, Bases>(
1072 m, outer, cls_name, doc,
1073 std::make_index_sequence<Bases.size()>{});
1074 })
1075 return B::template make_nested_class<T, decl, Bases>(
1076 m, outer, cls_name, doc,
1077 std::make_index_sequence<Bases.size()>{});
1078 else if constexpr (requires {
1079 B::template make_nested_class<T, Bases>(
1080 m, outer, cls_name, doc,
1081 std::make_index_sequence<Bases.size()>{});
1082 })
1083 return B::template make_nested_class<T, Bases>(
1084 m, outer, cls_name, doc,
1085 std::make_index_sequence<Bases.size()>{});
1086 else
1087 return make_class_of<B, T, decl, Bases>(m, cls_name, doc);
1088 }
1089
1105 template <rod B, class E>
1106 static auto make_enum_of(typename B::module_type& m, const char* name,
1107 const welder::detail::enum_doc& ed) {
1108 if constexpr (requires { B::template make_enum<E>(m, name, ed); })
1109 return B::template make_enum<E>(m, name, ed);
1110 else
1111 return B::template make_enum<E>(m, name, ed.summary);
1112 }
1113
1125 template <rod B, class E, class OuterCls>
1126 static auto make_nested_enum_of(typename B::module_type& m, OuterCls& outer,
1127 const char* name,
1128 const welder::detail::enum_doc& ed) {
1129 if constexpr (requires { B::template make_nested_enum<E>(m, outer, name, ed); })
1130 return B::template make_nested_enum<E>(m, outer, name, ed);
1131 else if constexpr (requires {
1132 B::template make_nested_enum<E>(m, outer, name,
1133 ed.summary);
1134 })
1135 return B::template make_nested_enum<E>(m, outer, name, ed.summary);
1136 else
1137 return make_enum_of<B, E>(m, name, ed);
1138 }
1139
1140 public:
1155 template <rod B, class E, class Style = naming::none>
1156 static auto bind_enum(typename B::module_type& m, const char* name = nullptr) {
1157 constexpr lang L{B::language};
1158 static_assert(Resolution::participates(^^E, L),
1159 "welder: weld_type<E>: enum E is not welded for this backend's "
1160 "language; annotate it with [[=welder::weld(...)]]");
1161 static_assert(!welder::has_no_reassign_mark(std::meta::dealias(^^E)),
1162 "welder: weld_type<E>: enum E carries "
1163 "[[=welder::mark::no_reassign]], but that forces a DATA "
1164 "MEMBER's read-only binding — it has no meaning on an enum");
1165 const char* enum_name{
1167 const auto docs{collect_enum_docs<B, E, Style>()};
1169 auto e{make_enum_of<B, E>(m, enum_name, ed)};
1171 B::template finish_enum<E>(e);
1172 return e;
1173 }
1174
1191 template <rod B, class T, std::meta::info Decl, auto Bases>
1192 static auto make_class_of(typename B::module_type& m, const char* cls_name,
1193 const char* doc) {
1194 if constexpr (requires {
1195 B::template make_class<T, Decl, Bases>(
1196 m, cls_name, doc,
1197 std::make_index_sequence<Bases.size()>{});
1198 })
1199 return B::template make_class<T, Decl, Bases>(
1200 m, cls_name, doc, std::make_index_sequence<Bases.size()>{});
1201 else
1202 return B::template make_class<T, Bases>(
1203 m, cls_name, doc, std::make_index_sequence<Bases.size()>{});
1204 }
1205
1237 template <rod B, class T, class Style = naming::none,
1238 std::meta::info Decl = std::meta::info{}>
1239 static auto bind_type(typename B::module_type& m, const char* name = nullptr) {
1240 constexpr lang L{B::language};
1241 static_assert(
1242 !std::meta::is_union_type(std::meta::dealias(^^T)),
1243 "welder: unions cannot be welded — C++ has no way to observe which "
1244 "union member is active, so generated member accessors would read "
1245 "inactive members (undefined behavior). Use std::variant instead "
1246 "(converted natively by every rod), or expose the union through "
1247 "safe accessor functions on an enclosing type. To hand-register it "
1248 "with the backend yourself, vouch for the uses via "
1249 "welder::trust_bindable.");
1250 static_assert(!welder::has_no_reassign_mark(std::meta::dealias(^^T)),
1251 "welder: weld_type<T>: T carries "
1252 "[[=welder::mark::no_reassign]], but that forces a DATA "
1253 "MEMBER's read-only binding — put it on a data member of T, "
1254 "not on the type");
1255 // Decl is the *declaring* entity when it differs from ^^T: the namespace-
1256 // scope alias through which a class-template specialization was welded
1257 // (bind_namespace's alias branch, which has already resolved participation
1258 // — the alias's own `weld` counts there, so ^^T alone can't be re-checked).
1259 static_assert(Decl != std::meta::info{} || Resolution::participates(^^T, L),
1260 "welder: weld_type<T>: T is not welded for this backend's "
1261 "language; annotate it with [[=welder::weld(...)]]");
1262 constexpr auto ctx{std::meta::access_context::unchecked()};
1263
1264 const char* cls_name{
1266
1267 // Native bases → bases of the class handle; the user binds them first.
1268 // A text-emitting rod that must *spell* the type in C++ (the trampoline
1269 // generator) declares the extended, declaring-entity-aware make_class; it
1270 // receives Decl — the alias, the one C++ name a specialization has — or
1271 // ^^T itself for a directly-declared class. Detected via requires, so the
1272 // runtime rods keep the plain form (they need only T + the bound name).
1273 constexpr auto bases{Resolution::template native_bases<^^T, L>()};
1274 auto cls{make_class_of<B, T, (Decl == std::meta::info{} ? ^^T : Decl),
1275 bases>(m, cls_name, welder::doc_of<^^T>())};
1276
1277 // Nested member types, constructors, data members / methods / operators
1278 // (shared with bind_nested_type — nesting recurses through it).
1280
1281 return cls;
1282 }
1283
1292 template <rod B, class T, class Style = naming::none,
1293 std::meta::info Decl = std::meta::info{}>
1294 static void predeclare_type(typename B::module_type& m,
1295 const char* name = nullptr) {
1296 constexpr lang L{B::language};
1297 static_assert(!std::meta::is_union_type(std::meta::dealias(^^T)),
1298 "welder: unions cannot be welded (see bind_type).");
1299 static_assert(Decl != std::meta::info{} || Resolution::participates(^^T, L),
1300 "welder: predeclare_type<T>: T is not welded for this "
1301 "backend's language.");
1302 const char* cls_name{
1304 constexpr auto bases{Resolution::template native_bases<^^T, L>()};
1305 // Create + register (name, bases, trampoline); the returned handle is
1306 // discarded — fill_type retrieves it by name in phase 3.
1307 make_class_of<B, T, (Decl == std::meta::info{} ? ^^T : Decl), bases>(
1308 m, cls_name, welder::doc_of<^^T>());
1309 }
1310
1317 template <rod B, class T, class Style = naming::none,
1318 std::meta::info Decl = std::meta::info{}>
1319 static void fill_type(typename B::module_type& m, const char* name = nullptr) {
1320 constexpr lang L{B::language};
1321 const char* cls_name{
1323 auto cls{B::template reopen_class<T>(m, cls_name)};
1325 }
1326
1345 template <rod B, std::meta::info Fn, class Style = naming::none>
1346 static auto bind_function(typename B::module_type& m, const char* name = nullptr) {
1347 constexpr lang L{B::language};
1348 static_assert(std::meta::is_function(Fn),
1349 "welder: weld_function<Fn>: Fn must reflect a (free) function");
1350 static_assert(Resolution::participates(Fn, L),
1351 "welder: weld_function<Fn>: Fn is not welded for this backend's "
1352 "language; annotate it with [[=welder::weld(...)]]");
1353 static_assert(!welder::has_accessor_mark(Fn),
1354 "welder: weld_function<Fn>: Fn carries a getter/setter "
1355 "mark, but properties are a class surface — the marks "
1356 "apply to member functions only");
1357 static_assert(!welder::has_no_reassign_mark(Fn),
1358 "welder: weld_function<Fn>: Fn carries "
1359 "[[=welder::mark::no_reassign]], but that forces a DATA "
1360 "MEMBER's read-only binding — it has no meaning on a function");
1362 template for (constexpr auto member : std::define_static_array(grp)) {
1364 }
1365 // Forward the rod's handle (the bound function object, where the
1366 // framework has one); a void-returning rod makes this void too.
1367 return B::template add_function<grp, Style>(m, name);
1368 }
1369
1385 template <rod B, std::meta::info Var, class Style = naming::none>
1386 static auto bind_variable(typename B::module_type& m, const char* name = nullptr) {
1387 constexpr lang L{B::language};
1388 static_assert(std::meta::is_variable(Var),
1389 "welder: weld_variable<Var>: Var must reflect a namespace "
1390 "variable");
1391 static_assert(!welder::has_no_reassign_mark(Var),
1392 "welder: weld_variable<Var>: Var carries "
1393 "[[=welder::mark::no_reassign]], but that forces a DATA "
1394 "MEMBER's read-only binding — it has no meaning on a global "
1395 "variable");
1396 static_assert(Resolution::participates(Var, L),
1397 "welder: weld_variable<Var>: Var is not welded for this "
1398 "backend's language; annotate it with [[=welder::weld(...)]]");
1400 auto session{B::open_module(m)};
1401 // Forward the rod's handle if its add_variable yields one (the shipped
1402 // rods return void — a bound constant is a snapshot, a mutable global a
1403 // module property; neither has a framework object worth returning), but
1404 // the session must still close after the registration.
1405 if constexpr (std::is_void_v<decltype(B::template add_variable<Var, Style>(
1406 m, session, name))>) {
1407 B::template add_variable<Var, Style>(m, session, name);
1408 B::close_module(m, session);
1409 } else {
1410 auto handle{B::template add_variable<Var, Style>(m, session, name)};
1411 B::close_module(m, session);
1412 return handle;
1413 }
1414 }
1415
1428 template <rod B, std::meta::info Ns, class Style = naming::none>
1429 static void bind_namespace(typename B::module_type& m) {
1430 static_assert(std::meta::is_namespace(Ns),
1431 "welder: weld_namespace<Ns>: Ns must reflect a namespace");
1432 constexpr lang L{B::language};
1433 constexpr auto ctx{std::meta::access_context::unchecked()};
1434 constexpr policy_kind pol{policy_of(Ns)};
1435
1436 // A [[=welder::doc]] on the namespace becomes the (sub)module docstring.
1437 if (const char* nsdoc{welder::doc_of<Ns>()})
1438 B::set_module_doc(m, nsdoc);
1439
1440 // The backend's per-module session: scratch state for attributes it emits in
1441 // one batch at the end (e.g. live variable properties). Opened before the
1442 // walk, finalized by close_module after it.
1443 auto session{B::open_module(m)};
1444
1445 // --- Two-phase sweep (opt-in rods: welder::two_phase_rod) ---------------
1446 // A rod that can RE-OPEN a class (the Python rods) binds a namespace in three
1447 // phases, so an opaque-container element type or a container-typed signature
1448 // is never bound before that type's NAME is registered — otherwise the
1449 // framework spells the raw C++ name in a docstring (a def-time-ordering
1450 // artifact stubgen rejects). PHASE 1 predeclares every welded class NAME
1451 // (create the handle, discard — fill_type retrieves it later) and fully binds
1452 // enums (they reference nothing, so they are name-safe anywhere). PHASE 2
1453 // binds every opaque container alias (all element names are now registered →
1454 // clean stubs; and a container an aggregate field defaults to is registered
1455 // before that field's synthesized constructor converts the default). The main
1456 // walk below is then PHASE 3 (fill): it RE-OPENS each class and fills its
1457 // members, with all containers already registered. A non-two-phase rod skips
1458 // both pre-passes; the main walk binds each class whole in one pass, as before.
1459 if constexpr (welder::two_phase_rod<B>) {
1460 // Phase 1 — predeclare class NAMES + fully bind enums.
1461 template for (constexpr auto mem :
1462 std::define_static_array(std::meta::members_of(Ns, ctx))) {
1463 if constexpr (std::meta::is_type_alias(mem) &&
1465 if constexpr (Resolution::alias_participates(mem, L, pol, Ns) &&
1467 std::meta::dealias(mem)))
1468 predeclare_type<B, typename [:mem:], Style, mem>(
1470 } else if constexpr (std::meta::is_type(mem) &&
1471 std::meta::is_class_type(mem)) {
1472 if constexpr (Resolution::member_participates(mem, L, pol, Ns))
1473 predeclare_type<B, typename [:mem:], Style>(m, nullptr);
1474 } else if constexpr (std::meta::is_type(mem) &&
1475 std::meta::is_enum_type(mem)) {
1476 if constexpr (Resolution::member_participates(mem, L, pol, Ns))
1477 bind_enum<B, typename [:mem:], Style>(m, nullptr);
1478 }
1479 }
1480 // Phase 2 — bind every opaque container alias (names registered above).
1481 if constexpr (welder::rod_binds_containers<B>) {
1482 template for (constexpr auto mem : std::define_static_array(
1483 std::meta::members_of(Ns, ctx))) {
1484 if constexpr (std::meta::is_type_alias(mem) &&
1487 std::meta::dealias(mem))) {
1488 if constexpr (Resolution::alias_participates(mem, L, pol,
1489 Ns)) {
1490 welder::assert_bindable<B, typename [:mem:], L,
1491 Resolution>();
1492 B::template bind_container<typename [:mem:], Style>(
1494 }
1495 }
1496 }
1497 }
1498 }
1499
1500 // The main walk. For a two-phase rod this is PHASE 3 (fill): classes RE-OPEN,
1501 // enums and containers are skipped (bound above). For any other rod it is the
1502 // single-pass sweep (each class bound whole).
1503 template for (constexpr auto mem :
1504 std::define_static_array(std::meta::members_of(Ns, ctx))) {
1505 // `no_reassign` is a data-member mark; nothing at namespace scope (a
1506 // function, a type, an alias, a global variable, a nested namespace) is
1507 // one, so the mark is always misplaced here — diagnosed, not ignored.
1508 // The kind guard runs FIRST so `&&` short-circuits before
1509 // has_no_reassign_mark (annotations_of throws on a template, which
1510 // members_of can yield).
1511 static_assert(
1512 !((std::meta::is_type(mem) || std::meta::is_function(mem) ||
1513 std::meta::is_variable(mem) || std::meta::is_namespace(mem)) &&
1515 "welder: [[=welder::mark::no_reassign]] sits on a namespace-scope "
1516 "entity, but it forces a DATA MEMBER's read-only binding — it has no "
1517 "meaning on a function, type, or global variable");
1518 // The alias branch must come first: type predicates (is_class_type)
1519 // look through an alias, so the class branch below would swallow it.
1520 if constexpr (std::meta::is_type_alias(mem)) {
1521 if constexpr (welder::names_template_specialization(mem)) {
1522 // The one way an *instantiation* enters a sweep (members_of
1523 // enumerates the template, never its specializations): the
1524 // alias is both the C++ spelling and the target-language name.
1525 static_assert(
1527 "welder: only weld / weld_as may be attached to a "
1528 "namespace-scope alias; every other mark belongs on the "
1529 "class template, where it applies to all instantiations");
1530 if constexpr (Resolution::alias_participates(mem, L, pol, Ns)) {
1531 static_assert(
1533 pol),
1534 "welder: two aliases in this namespace weld the SAME "
1535 "template specialization — each specialization may be "
1536 "welded under exactly one name");
1537 if constexpr (welder::is_reference_container(
1538 std::meta::dealias(mem))) {
1539 // A welded alias to std::vector / std::map /
1540 // std::unordered_map opts the container into *opaque,
1541 // reference-semantic* binding (bind_vector / bind_map)
1542 // instead of the copy caster — see containers.hpp. Only
1543 // the Python rods carry the hook; the Lua runtimes give
1544 // containers structural reference semantics already, so
1545 // welding such an alias for them is a designed error.
1546 static_assert(
1548 "welder: this alias welds an STL container "
1549 "(std::vector/std::map/std::unordered_map) for "
1550 "opaque, reference-semantic binding — a Python-rod "
1551 "feature (the Lua rods bind containers by reference "
1552 "structurally, needing no opaque alias). Drop the "
1553 "alias for this backend.");
1554 // Containers are bound in PHASE 2 above (a two-phase rod);
1555 // a non-two-phase rod that reaches here already tripped the
1556 // static_assert. Nothing to bind in this walk.
1557 } else if constexpr (welder::two_phase_rod<B>) {
1560 } else {
1563 }
1564 }
1565 } else {
1566 // An alias to a plain (non-template) type: binding it would
1567 // register the type a second time under the alias name — a
1568 // welded target makes the alias a likely mistake, diagnosed
1569 // rather than silently skipped. (Rename with weld_as instead.)
1570 static_assert(
1571 !((std::meta::is_class_type(std::meta::dealias(mem)) ||
1572 std::meta::is_enum_type(std::meta::dealias(mem))) &&
1573 welder::alias_welded_for(mem, L)),
1574 "welder: a namespace-scope alias to a welded NON-template "
1575 "type would bind the type twice (it already binds under "
1576 "its own name); remove the alias's weld, or rename the "
1577 "type with [[=welder::weld_as(...)]]");
1578 }
1579 } else if constexpr (std::meta::is_type(mem) &&
1580 std::meta::is_class_type(mem)) {
1581 // PHASE 3 fill (two-phase) reopens the predeclared class; a single-
1582 // pass rod binds it whole here.
1583 if constexpr (Resolution::member_participates(mem, L, pol, Ns)) {
1584 if constexpr (welder::two_phase_rod<B>)
1585 fill_type<B, typename [:mem:], Style>(m, nullptr);
1586 else
1588 }
1589 } else if constexpr (std::meta::is_type(mem) && std::meta::is_enum_type(mem)) {
1590 // Enums are fully bound in PHASE 1 for a two-phase rod (name-safe
1591 // anywhere), so they are skipped here; a single-pass rod binds them now.
1592 if constexpr (!welder::two_phase_rod<B> &&
1593 Resolution::member_participates(mem, L, pol, Ns))
1594 bind_enum<B, typename [:mem:], Style>(m, nullptr);
1595 } else if constexpr (std::meta::is_type(mem) &&
1596 std::meta::is_union_type(mem)) {
1597 // Unions never bind (reading an inactive member is UB — see
1598 // assert_bindable's union diagnostic). An unmarked union in a
1599 // swept namespace is simply skipped — its uses still fail the
1600 // gate — but a `weld` mark on one is an explicit attempt,
1601 // diagnosed loudly rather than silently ignored.
1602 static_assert(
1603 !welder::welded_for(mem, L),
1604 "welder: a union in this namespace carries "
1605 "[[=welder::weld(...)]], but unions cannot be welded — C++ "
1606 "has no way to observe which union member is active, so "
1607 "generated accessors would read inactive members (undefined "
1608 "behavior). Use std::variant instead (converted natively by "
1609 "every rod), or expose the union through safe accessor "
1610 "functions; hand-register it with the backend yourself via "
1611 "welder::trust_bindable on its uses.");
1612 } else if constexpr (std::meta::is_function(mem) &&
1613 !std::meta::is_operator_function(mem)) {
1614 // Free functions bind as whole overload groups, emitted at the
1615 // group's first participating overload (see bind_members).
1616 // OPERATOR functions are deliberately not functions here: a free
1617 // operator is part of its anchor type's interface (ADL), so the
1618 // type's own binding sweeps it (bind_operators) — and it has no
1619 // identifier for a module-level name anyway.
1620 static_assert(
1622 "welder: a getter/setter mark sits on a NAMESPACE-SCOPE "
1623 "function, but properties are a class surface — the marks "
1624 "apply to member functions only. Bind the free function as "
1625 "an ordinary module function (drop the mark), or wrap the "
1626 "pair in a class.");
1627 if constexpr (Resolution::member_participates(mem, L, pol, Ns)) {
1628 if constexpr (detail::is_overload_leader<
1630 mem, L, Ns)) {
1631 constexpr auto grp{detail::overload_group<
1633 Ns>()};
1634 template for (constexpr auto member :
1635 std::define_static_array(grp)) {
1637 Resolution>();
1638 }
1639 B::template add_function<grp, Style>(m);
1640 }
1641 }
1642 } else if constexpr (std::meta::is_variable(mem)) {
1643 if constexpr (Resolution::member_participates(mem, L, pol, Ns)) {
1645 B::template add_variable<mem, Style>(m, session);
1646 }
1647 } else if constexpr (std::meta::is_namespace(mem)) {
1648 // A nested namespace resolves like a leaf under the parent policy (but
1649 // is never welded): it becomes a submodule when it holds participating
1650 // content (then resolved under its *own* policy).
1651 if constexpr (Resolution::namespace_participates(mem, L, pol, Ns)) {
1652 auto sub{B::add_submodule(
1655 }
1656 }
1657 }
1658
1659 B::close_module(m, session);
1660 }
1661
1671 template <rod B, std::meta::info Ns, class Style = naming::none>
1672 static typename B::module_type bind_namespace_as_submodule(
1673 typename B::module_type& m, const char* name = nullptr) {
1674 static_assert(std::meta::is_namespace(Ns),
1675 "welder: weld_namespace_as_submodule<Ns>: Ns must reflect a "
1676 "namespace");
1677 typename B::module_type sub{B::add_submodule(
1678 m,
1681 return sub;
1682 }
1683
1697 template <rod B, std::meta::info Ns, class Style = naming::none, class Pre,
1698 class Post>
1699 static void build_module(typename B::module_type& m, Pre pre, Post post) {
1700 static_assert(std::meta::is_namespace(Ns),
1701 "welder: weld_module<Ns>: Ns must reflect a namespace");
1702 static_assert(std::meta::parent_of(Ns) == ^^::,
1703 "welder: weld_module<Ns>: Ns must be a top-level namespace (its "
1704 "name is meant to be the module name)");
1705 pre(m);
1707 post(m);
1708 }
1709};
1710
1711} // namespace carriages
1712
1717
1728
1731
1732} // namespace welder
Backend-agnostic selection layer: the reflection predicates and selectors that decide what participat...
Backend-agnostic bindability ("can the target language represent this type?").
The core interface concepts welder's static polymorphism rests on, gathered in one catalogue: the cus...
Does rod B implement the optional bind_container hook (i.e.
The contract a rod (a welder backend, welder::rods::…::rod) must satisfy to plug into the generic dri...
Definition concepts.hpp:263
Does rod B opt into the driver's two-phase namespace sweep — register every welded type's NAME,...
Definition concepts.hpp:101
The reference-semantic container table: which STL containers welder can bind opaquely* (by reference)...
Language-agnostic documentation layer: read [[=welder::doc(...)]] annotations off reflected entities ...
The stored forms of the annotation vocabulary.
consteval std::vector< property_entry > property_entries(std::meta::info type, lang L)
The resolved properties of type for language L: every participating accessor collected (own + flatten...
consteval bool is_overload_leader(std::meta::info fn, lang L, std::meta::info bound_into)
Whether fn is the first (declaration order) member of its Select overload set — the single visit on w...
consteval std::vector< std::meta::info > method_overload_set(std::meta::info fn, lang L, std::meta::info bound_into)
The participating method overloads sharing fn's name and static-ness, from the class where fn is decl...
consteval std::vector< std::meta::info > operator_entries(std::meta::info type, lang L)
Every participating operator entry of type's binding — member operators (own + flattened bases') and ...
consteval bool namespace_has_bound(std::meta::info ns, lang L)
Whether ns holds anything that would bind, directly or nested.
consteval bool sole_alias_of_target(lang L, policy_kind pol)
Is Alias the only participating alias in Ns welding its specialization?
Definition carriage.hpp:55
consteval auto ctor_group()
The participating constructors of Type under policy Pol: every bindable-shape constructor (see is_bin...
consteval std::vector< std::meta::info > stringifier_entries(std::meta::info type, lang L)
The participating stringifier entries for type: free operator<<(std::ostream&, T) overloads of its en...
consteval auto manual_function_group()
The semi-manual (weld_function<Fn>) group: Fn first — the user's named entity resolves the group's ta...
consteval std::vector< std::meta::info > function_overload_set(std::meta::info fn, lang L, std::meta::info bound_into)
The participating free-function overloads sharing fn's name, from fn's declaring namespace,...
consteval bool is_method_candidate(std::meta::info f)
The shape of a bindable method: a plain non-private member function.
consteval bool sole_member_alias_of_target(lang L, policy_kind pol)
Is Alias the only member alias of Outer whose participation would register its target?
Definition carriage.hpp:156
consteval auto overload_group()
Select's overload set for Fn as a fixed-size, splice-ready static array.
consteval bool copy_ctor_admitted()
Whether the resolution admits Type's copy constructor — the marks half of the copy decision; the carr...
consteval bool default_ctor_admitted()
Whether the resolution admits Type's DEFAULT constructor.
consteval std::array< bool, 4 > covered_comparison_slots(std::meta::info type, lang L)
Which relational slots (lt, le, gt, ge — indexed by cmp_slot) are already covered by an explicit part...
consteval bool namespace_has_bindable(std::meta::info ns, lang L)
The greedy twin of namespace_has_bound: whether ns holds any bindable kind (ignoring the weld marker)...
consteval const char * alias_bound_name()
The bound name of the type welded through Alias (a namespace-scope alias to a specialization,...
Definition carriage.hpp:90
consteval bool member_access_admitted(std::meta::info mem, lang L, std::meta::info bound_into)
Is mem's access level admitted for binding under Resolution?
consteval std::vector< std::meta::info > operator_slot_set(std::meta::info fn, lang L, std::meta::info bound_into)
The participating operator entries sharing fn's target slot (same operator and arity — hence the same...
consteval const char * property_bound_name()
The bound name of the property Getter defines, for language L under name style Style: the mark's expl...
consteval void validate_move_ctor_marks()
Reject an include/only mark on a move constructor of Type.
consteval bool registered_by_member_alias(std::meta::info scope, std::meta::info type, lang L)
Does a participating member alias of scope name type — i.e.
Definition carriage.hpp:187
consteval bool aggregate_initializable()
Whether to synthesize an aggregate field constructor for T (language L, resolution Resolution).
consteval bool nested_type_registered(std::meta::info type, lang L)
The GATE side of the nested-type sweep: does class-scoped type register with its enclosing class's bi...
Definition carriage.hpp:132
consteval auto native_base_types()
The native bases of Type for L as a static array of type reflections.
consteval bool welded_for(std::meta::info type, lang L)
Is type welded for language L — i.e.
Definition reflect.hpp:40
consteval void assert_callable_bindable()
Assert a function/method/operator/constructor signature binds, unless trusted.
Definition bindable.hpp:434
stitch_welding_carriage carriage
The default carriage — an alias for welder::stitch_welding_carriage.
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 void assert_bindable()
Hard error the instant welder would bind an unbindable type.
Definition bindable.hpp:344
consteval bool bindable()
Is T bindable to language L under backend B?
Definition bindable.hpp:330
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).
consteval bool member_alias_marks_admissible(std::meta::info mem)
May the annotations on member type-alias mem appear there?
Definition reflect.hpp:124
carriages::basic_carriage< carriages::marker_resolution > stitch_welding_carriage
The stitch-welding carriage (the default): binds only where welder's weld / policy / marks direct — i...
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
ent_kind
The nameable entity kinds welder distinguishes, one per name-style hook — picked by the driver/rod so...
Definition naming.hpp:320
@ class_
a class/struct type → transform_class.
Definition naming.hpp:321
@ enum_
an enum type → transform_enum.
Definition naming.hpp:322
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 const char * weld_as_of()
The verbatim weld_as name forced on Ent for language L, or nullptr.
Definition naming.hpp:343
consteval void assert_setter_bindable()
Assert a property setter's parameter binds, unless trusted — the write half of the getter/setter mach...
Definition bindable.hpp:453
consteval void assert_member_bindable()
Assert the type of a data member / namespace variable binds, unless trusted.
Definition bindable.hpp:422
carriages::basic_carriage< carriages::greedy_resolution<> > tack_welding_carriage
The tack-welding carriage: binds an unmarked library greedily — every reflectable type / function / g...
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
constexpr const char * name_of_or(const char *override_)
Resolve a bound name with a call-site override: override_ wins verbatim, nullptr falls back to name_o...
Definition naming.hpp:424
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 const char * name_of()
The final bound name of Ent (a K-kind entity) for language L under name style Style.
Definition naming.hpp:375
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 bool is_reference_container(std::meta::info type)
Is type one of the containers welder can bind by reference (opaquely)?
consteval const char * doc_of()
The doc text on Ent (a class, namespace, function, or parameter), or nullptr.
Definition doc.hpp:138
consteval bool is_nested_type(std::meta::info type)
Is type declared at class scope — a nested (member) type?
Definition carriage.hpp:106
consteval void assert_operands_bindable()
Assert the operand types of an operator<=> overload bind, unless the overload is trusted — the compar...
Definition bindable.hpp:497
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
Language-agnostic name styling: reshape a C++ identifier into a target language's naming convention,...
Language-agnostic resolution: given a reflected type/member and a target language,...
A carriage: welder's reflection-driven traversal, parameterized on a Resolution (which markers it obe...
Definition carriage.hpp:468
static auto bind_function(typename B::module_type &m, const char *name=nullptr)
Register free function Fn — with its participating overload siblings — as a module-level function of ...
static B::module_type bind_namespace_as_submodule(typename B::module_type &m, const char *name=nullptr)
Define a submodule of m and bind namespace Ns into it.
static void bind_nested_types(typename B::module_type &m, Cls &cls)
Register the participating member types of Outer onto its class handle cls — the nested-class / neste...
Definition carriage.hpp:892
static void fill_type(typename B::module_type &m, const char *name=nullptr)
Phase 3 of the two-phase sweep: RETRIEVE T's predeclared handle (via the rod's reopen_class) and fill...
static void bind_members(Cls &cls)
Flatten the eligible data members, methods and operators of Src onto the class handle cls (a handle f...
Definition carriage.hpp:491
static void predeclare_type(typename B::module_type &m, const char *name=nullptr)
Phase 1 of the two-phase sweep: register T's NAME only (create the class handle via make_class_of,...
static auto bind_type(typename B::module_type &m, const char *name=nullptr)
Reflect over T and register it via rod B onto module m.
static void bind_class_interior(typename B::module_type &m, Cls &cls)
Everything a class binding contains beyond the class handle itself — shared by bind_type (a module-sc...
Definition carriage.hpp:658
static void bind_nested_enum(typename B::module_type &m, OuterCls &outer, const char *name=nullptr)
static auto make_enum_of(typename B::module_type &m, const char *name, const welder::detail::enum_doc &ed)
Create the module-scope enum handle for E, folding its enumerator docs into the class docstring where...
static std::vector< welder::detail::enumerator_doc > collect_enum_docs()
Gather the documented, participating enumerators of E as welder::detail::enumerator_doc entries,...
Definition carriage.hpp:625
static void bind_namespace(typename B::module_type &m)
Reflect over a whole namespace Ns and expose its members on module m.
static auto make_nested_enum_of(typename B::module_type &m, OuterCls &outer, const char *name, const welder::detail::enum_doc &ed)
make_nested_class_of's enum counterpart: the rod's make_nested_enum when present, else the module-sco...
static auto bind_enum(typename B::module_type &m, const char *name=nullptr)
Reflect over enum E and register it via rod B onto module m.
static void bind_operators(Cls &cls)
Emit T's operators: member ones (own + flattened bases') and the anchored free operators** of T's enc...
Definition carriage.hpp:813
static auto make_class_of(typename B::module_type &m, const char *cls_name, const char *doc)
Call the rod's class-creation primitive, preferring the extended declaring-entity-aware form when the...
static void bind_properties(Cls &cls)
Emit T's method-backed properties: every accessor-marked member function (own + flattened bases',...
Definition carriage.hpp:770
static auto bind_variable(typename B::module_type &m, const char *name=nullptr)
Register a single namespace variable Var as an attribute of m.
static void build_module(typename B::module_type &m, Pre pre, Post post)
Fill an existing module out of top-level namespace Ns: pre hook, bind the namespace,...
static void bind_nested_type(typename B::module_type &m, OuterCls &outer, const char *name=nullptr)
Register nested class T onto the class handle of its enclosing type — bind_type's class-scope sibling...
Definition carriage.hpp:998
static auto make_nested_class_of(typename B::module_type &m, OuterCls &outer, const char *cls_name, const char *doc)
static void emit_enumerators(EnumHandle &e)
The per-enumerator walk shared by bind_enum and bind_nested_enum: each enumerator resolves like a dat...
Definition carriage.hpp:598
Tack-welding resolution: bind an unmarked library greedily.
Definition carriage.hpp:365
static consteval bool alias_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
Greedy: an alias-declared specialization binds like any other type — no weld needed on alias or templ...
Definition carriage.hpp:382
static consteval bool protected_participates(std::meta::info mem, lang L, std::meta::info)
Protected members: the WeldProtected knob (the whole-pass blanket for an unannotatable third-party li...
Definition carriage.hpp:399
static consteval bool is_native_base(std::meta::info, lang, std::meta::info)
Definition carriage.hpp:367
static consteval auto native_bases()
Definition carriage.hpp:372
static consteval bool counts_as_registered(std::meta::info type, lang L)
The gate's registration oracle: a type the greedy pass itself registers — any complete class/enum who...
Definition carriage.hpp:433
static consteval bool namespace_participates(std::meta::info ns, lang L, policy_kind pol, std::meta::info)
Definition carriage.hpp:404
static consteval bool class_member_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
Same as stitch: greedy ignores the weld marker, not the marks — a mark on an individual overload/cons...
Definition carriage.hpp:389
static consteval bool member_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
Definition carriage.hpp:375
static consteval bool participates(std::meta::info, lang)
Definition carriage.hpp:366
Stitch-welding resolution: bind only where welder's markers say to.
Definition carriage.hpp:255
static consteval bool counts_as_registered(std::meta::info type, lang L)
The gate's registration oracle: welded ⇒ registered (the welder::welded_registration rule),...
Definition carriage.hpp:331
static consteval bool class_member_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
A class member (field / method / operator / constructor — and, loosely, an enumerator) participates: ...
Definition carriage.hpp:297
static consteval bool participates(std::meta::info entity, lang L)
A type/function/variable participates iff welded for L.
Definition carriage.hpp:257
static consteval bool is_native_base(std::meta::info base, lang L, std::meta::info)
A base is a separately-registered native base iff the user welded it.
Definition carriage.hpp:263
static consteval auto native_bases()
T's native (welded) base list, for the class handle.
Definition carriage.hpp:269
static consteval bool alias_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
A namespace-scope alias to a class-template specialization participates: welded via the alias's own w...
Definition carriage.hpp:284
static consteval bool namespace_participates(std::meta::info ns, lang L, policy_kind pol, std::meta::info)
A nested namespace participates (recurse + submodule).
Definition carriage.hpp:318
static consteval bool member_participates(std::meta::info mem, lang L, policy_kind pol, std::meta::info)
A namespace member (class/enum/function/variable) participates.
Definition carriage.hpp:275
static consteval bool protected_participates(std::meta::info mem, lang L, std::meta::info)
A protected member is admitted iff its declaring class says so — a policy::weld_protected annotation ...
Definition carriage.hpp:312
The raw documentation pieces of an enum, handed to a style to assemble.
Definition doc.hpp:277
const char * summary
The enum's own doc.
Definition doc.hpp:278
The scope-aware registration oracle: Resolution widened with the member-alias registrations of one cl...
Definition carriage.hpp:222
static consteval bool counts_as_registered(std::meta::info type, lang L)
Definition carriage.hpp:223
The identity style: bind every C++ identifier unchanged.
Definition naming.hpp:259