|
welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
|
Namespaces | |
| namespace | detail |
Classes | |
| struct | by_value_spec |
| The stored form of a by_value mark (a plain tag — it carries no state). More... | |
| struct | google_style |
| Google-style docstring assembly (the default). More... | |
| struct | numpy_style |
| NumPy-style docstring assembly (numpydoc). More... | |
| struct | pep8 |
| PEP 8 naming: CapWords (PascalCase) for classes and enum types, snake_case for everything callable or data — methods, static methods, free functions, data members (properties), namespace variables — and submodules. More... | |
| struct | scanned_trampoline |
| The outcome of scanning a base's namespace for its trampoline-annotated subclass. More... | |
| struct | sphinx_style |
| Sphinx-style docstring assembly (reStructuredText field lists). More... | |
| struct | trampoline_spec |
| The stored form of a trampoline mark (a plain tag — it carries no state). More... | |
Functions | |
| consteval std::string | ai_uint_string (std::size_t n) |
| Decimal render of n (constexpr std::to_string is unavailable on gcc-16). | |
| consteval bool | ai_is_unsigned (std::meta::info t) |
| Is t one of the unsigned integer fundamental types? | |
| consteval std::string | numpy_typestr (std::meta::info t) |
| The NumPy typestr for arithmetic type t ('<' little-endian, '|' for a single byte), or "" if t has no portable NumPy scalar type (a non-arithmetic type, or long double). | |
| template<class E> | |
| consteval const char * | ai_typestr () |
| The array-interface typestr for the whole element E — an opaque |V<sizeof> void field; the per-field ai_descr carries the meaning. | |
| consteval bool | ai_all_fields_numpy (std::meta::info E) |
| Whether every one of a POD struct's fields maps to a NumPy scalar (so the descr is complete). | |
| template<class E> | |
| consteval bool | pod_array_eligible () |
| Is std::vector<E> viewable as a NumPy structured array — i.e. | |
| consteval std::size_t | ai_entry_count (std::meta::info E) |
| The number of array-interface descr entries for E — one per field, plus one per padding gap (interior or trailing). | |
| template<std::meta::info E> | |
| consteval std::array< std::pair< const char *, const char * >, ai_entry_count(E)> | ai_descr () |
| The NumPy array-interface descr for E: a splice-ready std::array of (name, typestr) pairs — each field in declaration order, with ("", "|V<gap>") void entries for interior and trailing padding so the itemsize and field offsets match E's layout exactly. | |
| consteval bool | marked_by_value (std::meta::info entity) |
| Does entity carry a by_value mark? | |
| consteval const char * | operator_dunder (std::meta::info f) |
| The Python special-method ("dunder") name for an operator (member or anchored free), or nullptr if welder does not expose that operator. | |
| consteval const char * | reflected_dunder (std::meta::info f) |
| The reflected ("swapped-operand") dunder for a free operator whose anchor type is the right operand — operator*(double, Vec) binds on Vec as __rmul__, so 2.0 * v works from Python exactly as from C++. | |
| consteval bool | dunder_uses_not_implemented (std::meta::info f) |
| Whether f's slot participates in Python's NotImplemented protocol — every binary arithmetic / bitwise / shift / comparison dunder (reflected forms included), where a failed operand conversion must return NotImplemented so Python tries the other operand's reflected method, rather than raise TypeError. | |
| consteval const char * | cmp_slot_dunder (::welder::detail::cmp_slot s) |
| The dunder each synthesized comparison slot binds under (see the rods' add_comparisons and welder::detail::synthesized_comparison). | |
| template<class T, auto Fns, auto Covered, class Def> | |
| void | synthesize_comparisons (Def def) |
| The comparison-synthesis walk shared by both Python backends: for each operator<=> overload in Fns, hand def a (welder::detail::synthesized_comparison function pointer, dunder name) pair per relational slot not already Covered by an explicit operator. | |
| consteval bool | is_trampoline (std::meta::info type) |
| Does type carry a trampoline mark? | |
| consteval scanned_trampoline | scanned_trampoline_of (std::meta::info base) |
| Find the trampoline-annotated class deriving directly from base by scanning base's enclosing namespace. | |
| template<class T> | |
| consteval std::meta::info | construction_type_of () |
| The type welder constructs when binding T: its registered/annotated trampoline if one exists, else T itself. | |
| consteval bool | declares_override (std::meta::info tramp, std::meta::info vfn) |
| Does trampoline declare an override for the virtual method vfn? | |
| consteval bool | trampoline_covers (std::meta::info type, std::meta::info tramp) |
| Does tramp override every virtual method of type — inherited ones included? | |
Variables | |
| constexpr by_value_spec | by_value {} |
| Opt a data member's container type out of the opaque-container generator — it keeps default by-value (copy) binding. | |
| template<class T> | |
| constexpr std::meta::info | trampoline_for = std::meta::info{} |
| The trampoline subclass registered for T, or a null reflection if none. | |
| constexpr trampoline_spec | trampoline {} |
| Mark a class as the trampoline for the base it derives from — the annotation form of trampoline_for. | |
|
consteval |
Whether every one of a POD struct's fields maps to a NumPy scalar (so the descr is complete).
A field-less struct or one with a non-arithmetic field is ineligible.
Definition at line 84 of file array_interface.hpp.
References numpy_typestr().
Referenced by pod_array_eligible().
|
consteval |
The NumPy array-interface descr for E: a splice-ready std::array of (name, typestr) pairs — each field in declaration order, with ("", "|V<gap>") void entries for interior and trailing padding so the itemsize and field offsets match E's layout exactly.
The rods materialize this into the descr list at runtime (the const char*s are static, so the array iterates as ordinary data).
Definition at line 132 of file array_interface.hpp.
References ai_entry_count(), ai_uint_string(), and numpy_typestr().
|
consteval |
The number of array-interface descr entries for E — one per field, plus one per padding gap (interior or trailing).
Definition at line 107 of file array_interface.hpp.
Referenced by ai_descr().
|
consteval |
Is t one of the unsigned integer fundamental types?
(std::meta has no is_signed, so the unsigned set is enumerated.)
Definition at line 43 of file array_interface.hpp.
Referenced by numpy_typestr().
|
consteval |
The array-interface typestr for the whole element E — an opaque |V<sizeof> void field; the per-field ai_descr carries the meaning.
Definition at line 78 of file array_interface.hpp.
References ai_uint_string().
|
consteval |
Decimal render of n (constexpr std::to_string is unavailable on gcc-16).
Definition at line 32 of file array_interface.hpp.
Referenced by ai_descr(), ai_typestr(), and numpy_typestr().
|
consteval |
The dunder each synthesized comparison slot binds under (see the rods' add_comparisons and welder::detail::synthesized_comparison).
| s | the relational slot. |
Definition at line 131 of file operators.hpp.
Referenced by synthesize_comparisons().
|
consteval |
The type welder constructs when binding T: its registered/annotated trampoline if one exists, else T itself.
A rod exposes this (as construction_type<T>) so the driver decides constructibility against the concrete trampoline rather than T. That matters for an abstract base: std::is_default_constructible_v<T> is false, so the driver would register no constructor and a Python subclass could not be instantiated — but the trampoline is constructible, so binding it keeps the subclass usable. For a concrete T the trampoline is constructible exactly when T is, so the substitution changes nothing.
| T | the welded type. |
Definition at line 152 of file trampoline.hpp.
References welder::has_virtual_methods(), scanned_trampoline_of(), and trampoline_for.
|
consteval |
Does trampoline declare an override for the virtual method vfn?
A trampoline overrides vfn by redeclaring a member function with the same name and the same signature; members_of lists a class's own members (not inherited ones), so an un-overridden virtual is simply absent. Matching is by name plus type_of equality — the reflected function type, which bundles the parameter types, cv-qualification, and ref-qualifier (independent of the declaring class). That distinguishes a real override from an unrelated same-named overload or a const/ref-qualifier mismatch, which name-plus-arity alone would not.
| tramp | a reflection of the trampoline subclass. |
| vfn | a reflection of a base virtual member function. |
Definition at line 179 of file trampoline.hpp.
Referenced by trampoline_covers().
|
consteval |
Whether f's slot participates in Python's NotImplemented protocol — every binary arithmetic / bitwise / shift / comparison dunder (reflected forms included), where a failed operand conversion must return NotImplemented so Python tries the other operand's reflected method, rather than raise TypeError.
__call__ and __getitem__ are excluded (there TypeError IS the protocol), as are the unary slots. The Python rods pass is_operator() on exactly these defs.
| f | a reflection of the operator function. |
Definition at line 116 of file operators.hpp.
References welder::detail::is_unary_operator(), and operator_dunder().
Referenced by welder::rods::nanobind::rod< DocStyle >::add_operator(), and welder::rods::pybind11::rod< DocStyle >::add_operator().
|
consteval |
Does type carry a trampoline mark?
| type | a reflection of the class to test. |
Definition at line 97 of file trampoline.hpp.
Referenced by scanned_trampoline_of().
|
consteval |
Does entity carry a by_value mark?
| entity | a reflection of the member. |
Definition at line 37 of file marks.hpp.
Referenced by welder::rods::opaque_containers::rod::add_field().
|
consteval |
The NumPy typestr for arithmetic type t ('<' little-endian, '|' for a single byte), or "" if t has no portable NumPy scalar type (a non-arithmetic type, or long double).
float→"<f4", double→"<f8", bool→"|b1", signed/unsigned integers by size — int→"<i4", unsigned char→"|u1", std::int64_t→"<i8", …
Definition at line 59 of file array_interface.hpp.
References ai_is_unsigned(), and ai_uint_string().
Referenced by ai_all_fields_numpy(), and ai_descr().
|
consteval |
The Python special-method ("dunder") name for an operator (member or anchored free), or nullptr if welder does not expose that operator.
Unary vs binary is told apart by arity (welder::detail::is_unary_operator — a member operator's left operand is implicit, a free one spells both out), disambiguating the operators that have both forms (+, -). In-place compound assignments (operator+=, …) are intentionally not mapped: Python already falls back to the binary form (a += b → a = a + b via __add__) with correct value semantics, and binding __iadd__ faithfully would need a reference return policy. Likewise &&, ||, ++, -- and = have no clean reflection-driven Python mapping. operator<=> never binds under a dunder of its own — it synthesizes the relational slots instead (see the rods' add_comparisons).
| f | a reflection of the operator function. |
Definition at line 41 of file operators.hpp.
References welder::detail::is_unary_operator().
Referenced by welder::rods::nanobind::rod< DocStyle >::add_operator(), welder::rods::pybind11::rod< DocStyle >::add_operator(), and dunder_uses_not_implemented().
|
consteval |
Is std::vector<E> viewable as a NumPy structured array — i.e.
is E a trivially-copyable, standard-layout class whose fields are all NumPy scalars? Excludes scalars (they take the buffer-protocol path) and, by construction, any vtable'd / string-holding / pointer-holding type (not trivially copyable).
Definition at line 100 of file array_interface.hpp.
References ai_all_fields_numpy().
Referenced by welder::rods::pybind11::rod< DocStyle >::_bind_array(), welder::rods::nanobind::rod< DocStyle >::_numpy_view(), and welder::rods::pybind11::rod< DocStyle >::bind_container().
|
consteval |
The reflected ("swapped-operand") dunder for a free operator whose anchor type is the right operand — operator*(double, Vec) binds on Vec as __rmul__, so 2.0 * v works from Python exactly as from C++.
A comparison's reflected pair is its mirror image (Python has no __rlt__: 5 < v falls through to v.__gt__(5)), and ==/!= are their own mirrors. The rod binds such an entry through an operand-swapping wrapper (the C++ operator still receives its operands in declaration order).
| f | a reflection of the (binary, anchored-right) free operator. |
Definition at line 79 of file operators.hpp.
References welder::detail::is_unary_operator().
Referenced by welder::rods::nanobind::rod< DocStyle >::_def_reflected_operator(), and welder::rods::pybind11::rod< DocStyle >::_def_reflected_operator().
|
consteval |
Find the trampoline-annotated class deriving directly from base by scanning base's enclosing namespace.
The discovery half of the annotation form (trampoline): with no global type enumeration in reflection, a trampoline is reachable from its base only by scanning a known scope — here base's own namespace. Zero matches → a null reflection; two or more → scanned_trampoline::ambiguous (resolve with trampoline_for).
| base | a reflection of the welded base type. |
Definition at line 117 of file trampoline.hpp.
References welder::rods::python::scanned_trampoline::ambiguous, is_trampoline(), and welder::rods::python::scanned_trampoline::type.
Referenced by construction_type_of().
| void welder::rods::python::synthesize_comparisons | ( | Def | def | ) |
The comparison-synthesis walk shared by both Python backends: for each operator<=> overload in Fns, hand def a (welder::detail::synthesized_comparison function pointer, dunder name) pair per relational slot not already Covered by an explicit operator.
The wrapper is a plain rewritten expression over (T, the overload's operand type), so C++'s own rewriting semantics carry over verbatim.
| T | the welded type. |
| Fns | the spaceship overload group (a static array of reflections). |
| Covered | the explicitly-covered slot flags, indexed by welder::detail::cmp_slot. |
| def | a callable receiving (const char* dunder, bool (*)(…)). |
Definition at line 153 of file operators.hpp.
References cmp_slot_dunder(), and welder::detail::comparison_operand().
Referenced by welder::rods::nanobind::rod< DocStyle >::add_comparisons(), and welder::rods::pybind11::rod< DocStyle >::add_comparisons().
|
consteval |
Does tramp override every virtual method of type — inherited ones included?
The coverage guard behind welder's compile-time check: a virtual left un-overridden would bind, but calls to it from C++ would never dispatch into a Python override. Iterates overridable_virtuals, so a virtual type merely inherits* must also be redeclared in tramp (its dispatch runs through type's own trampoline, not the base's). tramp is scanned by declares_override, which lists tramp's own members — so the trampoline is expected to redeclare every override itself, inherited slots included.
| type | a reflection of the welded base type. |
| tramp | a reflection of its registered trampoline. |
Definition at line 203 of file trampoline.hpp.
References declares_override(), and welder::overridable_virtuals().
|
inlineconstexpr |
Opt a data member's container type out of the opaque-container generator — it keeps default by-value (copy) binding.
|
inlineconstexpr |
Mark a class as the trampoline for the base it derives from — the annotation form of trampoline_for.
Usage: struct [[=welder::rods::python::trampoline]] PyAnimal : Animal { … };. welder infers the base from the trampoline's own base list and discovers the trampoline by scanning that base's namespace (see scanned_trampoline_of), so no explicit T → trampoline mapping is written. Requires the trampoline to live in the same namespace as its welded base (reflection offers no global type enumeration, so discovery must scan a known scope). For a third-party base, a trampoline kept in a different namespace, or to disambiguate, specialize trampoline_for instead — it wins when both are present.
Definition at line 92 of file trampoline.hpp.
|
constexpr |
The trampoline subclass registered for T, or a null reflection if none.
Specialize this in the binding translation unit — where the concrete, backend-specific trampoline is defined — to tell welder's Python rods to bind class_<T, Trampoline> so Python subclasses can override T's virtual methods:
It is the type-level counterpart of welder::trust_bindable — a hook usable even for third-party types you cannot annotate, and it takes precedence over the annotation form (trampoline).
| T | the welded type. |
Definition at line 73 of file trampoline.hpp.
Referenced by construction_type_of().