welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
welder::rods::python Namespace Reference

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.

Function Documentation

◆ ai_all_fields_numpy()

bool welder::rods::python::ai_all_fields_numpy ( std::meta::info E)
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().

◆ ai_descr()

template<std::meta::info E>
std::array< std::pair< const char *, const char * >, ai_entry_count(E)> welder::rods::python::ai_descr ( )
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().

◆ ai_entry_count()

std::size_t welder::rods::python::ai_entry_count ( std::meta::info E)
consteval

The number of array-interface descr entries for E — one per field, plus one per padding gap (interior or trailing).

See also
ai_descr

Definition at line 107 of file array_interface.hpp.

Referenced by ai_descr().

◆ ai_is_unsigned()

bool welder::rods::python::ai_is_unsigned ( std::meta::info t)
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().

◆ ai_typestr()

template<class E>
const char * welder::rods::python::ai_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().

◆ ai_uint_string()

std::string welder::rods::python::ai_uint_string ( std::size_t n)
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().

◆ cmp_slot_dunder()

const char * welder::rods::python::cmp_slot_dunder ( ::welder::detail::cmp_slot s)
consteval

The dunder each synthesized comparison slot binds under (see the rods' add_comparisons and welder::detail::synthesized_comparison).

Parameters
sthe relational slot.
Returns
the dunder name (static storage).

Definition at line 131 of file operators.hpp.

Referenced by synthesize_comparisons().

◆ construction_type_of()

template<class T>
std::meta::info welder::rods::python::construction_type_of ( )
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.

Template Parameters
Tthe welded type.
Returns
a reflection of the trampoline type (registered via trampoline_for or discovered via the trampoline annotation), or of T if none.

Definition at line 152 of file trampoline.hpp.

References welder::has_virtual_methods(), scanned_trampoline_of(), and trampoline_for.

◆ declares_override()

bool welder::rods::python::declares_override ( std::meta::info tramp,
std::meta::info vfn )
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.

Note
The slot vfn is the most-derived declaration (overridable_virtuals), so for a covariant chain the trampoline redeclares the narrowed signature — which is what a hand-written override must spell anyway.
Parameters
trampa reflection of the trampoline subclass.
vfna reflection of a base virtual member function.
Returns
true iff tramp redeclares vfn with a matching signature.

Definition at line 179 of file trampoline.hpp.

Referenced by trampoline_covers().

◆ dunder_uses_not_implemented()

bool welder::rods::python::dunder_uses_not_implemented ( std::meta::info f)
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.

Parameters
fa reflection of the operator function.
Returns
true iff the def should carry the backend's is_operator tag.

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().

◆ is_trampoline()

bool welder::rods::python::is_trampoline ( std::meta::info type)
consteval

Does type carry a trampoline mark?

Parameters
typea reflection of the class to test.
Returns
true iff type is annotated as a trampoline.

Definition at line 97 of file trampoline.hpp.

Referenced by scanned_trampoline_of().

◆ marked_by_value()

bool welder::rods::python::marked_by_value ( std::meta::info entity)
consteval

Does entity carry a by_value mark?

Parameters
entitya reflection of the member.

Definition at line 37 of file marks.hpp.

Referenced by welder::rods::opaque_containers::rod::add_field().

◆ numpy_typestr()

std::string welder::rods::python::numpy_typestr ( std::meta::info t)
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().

◆ operator_dunder()

const char * welder::rods::python::operator_dunder ( std::meta::info f)
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 += ba = 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).

Parameters
fa reflection of the operator function.
Returns
the dunder name (static storage), or nullptr.

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().

◆ pod_array_eligible()

template<class E>
bool welder::rods::python::pod_array_eligible ( )
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().

◆ reflected_dunder()

const char * welder::rods::python::reflected_dunder ( std::meta::info f)
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).

Parameters
fa reflection of the (binary, anchored-right) free operator.
Returns
the reflected dunder name (static storage), or nullptr.

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().

◆ scanned_trampoline_of()

scanned_trampoline welder::rods::python::scanned_trampoline_of ( std::meta::info base)
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).

Parameters
basea reflection of the welded base type.
Returns
the scan outcome.

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().

◆ synthesize_comparisons()

template<class T, auto Fns, auto Covered, class Def>
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.

Template Parameters
Tthe welded type.
Fnsthe spaceship overload group (a static array of reflections).
Coveredthe explicitly-covered slot flags, indexed by welder::detail::cmp_slot.
Parameters
defa 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().

◆ trampoline_covers()

bool welder::rods::python::trampoline_covers ( std::meta::info type,
std::meta::info tramp )
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.

Parameters
typea reflection of the welded base type.
trampa reflection of its registered trampoline.
Returns
true iff every overridable virtual of type is redeclared in tramp.

Definition at line 203 of file trampoline.hpp.

References declares_override(), and welder::overridable_virtuals().

Variable Documentation

◆ by_value

by_value_spec welder::rods::python::by_value {}
inlineconstexpr

Opt a data member's container type out of the opaque-container generator — it keeps default by-value (copy) binding.

See also
by_value_spec

Definition at line 34 of file marks.hpp.

◆ trampoline

trampoline_spec welder::rods::python::trampoline {}
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.

See also
trampoline_spec

Definition at line 92 of file trampoline.hpp.

◆ trampoline_for

template<class T>
std::meta::info welder::rods::python::trampoline_for = std::meta::info{}
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:

template <> constexpr std::meta::info
constexpr std::meta::info trampoline_for
The trampoline subclass registered for T, or a null reflection if none.

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).

Template Parameters
Tthe welded type.

Definition at line 73 of file trampoline.hpp.

Referenced by construction_type_of().