|
welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
|
The nanobind rod: a stateless policy type satisfying welder::rod. More...
#include <welder/rods/python/nanobind/rod.hpp>
Public Types | |
| using | module_type = nb::module_ |
| nanobind's module handle. | |
| template<class E> | |
| using | enum_handle_type = nb::enum_<E> |
| The enum handle make_enum yields — exactly its return type. | |
| template<class T> | |
| using | construction_type |
| The type welder constructs when binding T — its registered trampoline if one exists, else T — so an abstract base with a trampoline stays constructible from a Python subclass. | |
| template<class T> | |
| using | class_handle_type |
| The class handle make_class yields for T — exactly its return type for a base-less T (so it captures the woven-in trampoline for a virtual T); the single welded base nanobind supports is chosen by the carriage's resolution, not by T, so it is appended by make_class and is not a function of T alone. | |
Static Public Member Functions | |
| static consteval const char * | special_method_name (std::meta::info op_fn) |
| Map a member operator to its Python dunder (nullptr = not exposed). | |
| template<class T, auto Bases, std::size_t... I> | |
| static auto | make_class (module_type &m, const char *name, const char *doc, std::index_sequence< I... > seq) |
| Create the nb::class_<T, Bases…> handle, weaving in a trampoline when T is a welded virtual type with a registered welder::rods::python::trampoline_for. | |
| template<class T, auto Bases, std::size_t... I> | |
| static auto | make_nested_class (module_type &, auto &outer_cls, const char *name, const char *doc, std::index_sequence< I... > seq) |
| Create the nb::class_ for a nested member type T, registered under its enclosing type's class handle rather than the module — Python then sees it as module.Outer.Inner (and __qualname__ nests), exactly like a hand-written nb::class_<Outer::Inner>(outer_cls, "Inner"). | |
| template<class T> | |
| static class_handle_type< T > | reopen_class (module_type &scope, const char *name) |
| Retrieve the ALREADY-registered class T as a fillable handle — the two-phase binding hook (optional; declaring it opts the rod into the driver's two-phase namespace sweep). | |
| template<class T> | |
| static class_handle_type< T > | reopen_nested_class (module_type &, auto &outer, const char *name) |
| The nested-scope form of reopen_class — retrieve T from its enclosing type's class handle (outer.attr(name)). | |
| template<class T, auto Ctors, bool HasDefault, bool Aggregate, bool Copyable, class Style = ::welder::naming::none> | |
| static void | add_constructors (auto &cls) |
| Bind T's whole constructor set (a chained-def framework just loops it): the default constructor when HasDefault, an nb::init<…> per member of Ctors, and the synthesized aggregate field constructor when Aggregate. | |
| template<class D> | |
| static void | _def_erased_field (nb::handle cls, const char *name, std::size_t offset, bool read_only, const char *doc) |
| Bind one field as a property through CLASS-ERASED accessors: the closures capture the member's byte offset as runtime state and take nb::handle self, so their closure TYPE — and therefore nanobind's func_create instantiation — depends only on the field type D. | |
| template<std::meta::info Mem, class Style = ::welder::naming::none> | |
| static void | add_field (auto &cls) |
| Bind data member Mem as an attribute. | |
| template<class T, std::meta::info Getter, std::meta::info Setter> | |
| static void | add_property (auto &cls, const char *name) |
| Bind the resolved property (Getter + optional Setter) as a Python property named name (driver-resolved). | |
| template<auto Fns, class Style = ::welder::naming::none> | |
| static void | add_method (auto &cls) |
| Bind method overload group Fns (name from Fns[0]; nanobind chains one .def per overload and dispatches at call time). | |
| template<auto Fns, class Style = ::welder::naming::none> | |
| static void | add_static_method (auto &cls) |
| Bind static-method overload group Fns. | |
| template<class T, auto Fns> | |
| static void | add_operator (auto &cls) |
| Bind operator slot group Fns — one (operator, arity) slot whole, member and anchored free entries mixed. | |
| template<class T, auto Fns, auto Covered> | |
| static void | add_comparisons (auto &cls) |
| Synthesize the relational dunders from operator<=> group Fns via rewritten expressions (a < b, …), skipping the slots an explicit participating operator already Covered — the same semantics as the pybind11 rod (the shared walk is welder::rods::python::synthesize_comparisons). | |
| template<class T, std::meta::info Fn> | |
| static void | add_stringifier (auto &cls) |
| Bind the swept free ostream inserter Fn as __str__ (via welder::detail::stringify). | |
| template<class E> | |
| static auto | make_enum (module_type &m, const char *name, const ::welder::detail::enum_doc &ed) |
| Create the nb::enum_<E> handle (a non-null doc becomes its docstring). | |
| template<class E> | |
| static auto | make_nested_enum (module_type &, auto &outer_cls, const char *name, const ::welder::detail::enum_doc &ed) |
| Create the nb::enum_<E> for a nested member enum, scoped to its enclosing type's class handle — Python sees module.Outer.Mode, and an unscoped* nested enum's export_values() lands its enumerators on the class (mirroring C++'s Outer::red). | |
| template<std::meta::info Enum, class Style = ::welder::naming::none> | |
| static void | add_enumerator (auto &e) |
| Add enumerator Enum to the enum handle. | |
| template<class E> | |
| static void | finish_enum (auto &e) |
| Finalize enum E: export an unscoped enum's values into the enclosing scope. | |
| static nb::dict | open_module (module_type &) |
| Open a per-module session: a dict accumulating live (mutable-variable) properties; _install_live_properties() applies them in one __class__ swap at close. | |
| static void | set_module_doc (module_type &m, const char *doc) |
| Set the (sub)module docstring. | |
| template<auto Fns, class Style = ::welder::naming::none> | |
| static nb::object | add_function (module_type &m, const char *name=nullptr) |
| Bind free-function overload group Fns as one module-level function (name from Fns[0]; one chained .def per overload). | |
| template<std::meta::info Var, class Style = ::welder::naming::none> | |
| static void | add_variable (module_type &m, nb::dict &live, const char *name_override=nullptr) |
| Bind namespace variable Var as a module attribute. | |
| static module_type | add_submodule (module_type &m, const char *name) |
| Create a submodule named name under m. | |
| template<class Container, class Style = ::welder::naming::none> | |
| static void | bind_container (module_type &m, const char *name) |
| Bind STL Container opaquely — by reference, with live mutation — under name, the driver's route for a welded container alias (see <welder/containers.hpp>). | |
| template<class Container> | |
| static void | _bind_array (module_type &m, const char *name) |
| Bind fixed-size sequence Container (std::array<T, N>) opaquely — by reference, with element write-through — under name. | |
| template<class Container, class Cls> | |
| static void | _numpy_view (Cls &cls) |
| Give contiguous sequence class cls the zero-copy NumPy view its element type supports: an __array__ returning a live nb::ndarray for an arithmetic (non-bool) element, or the structured __array_interface__ dict for a POD struct element (_array_interface). | |
| static std::size_t | _wrap_index (Py_ssize_t i, std::size_t n) |
| Normalize a Python index i (allowing one level of negative wrap-around) against length n, raising IndexError when out of range — the fixed-array __getitem__/__setitem__ bounds check (the bind_vector wrap analogue, reproduced here so the array path does not lean on a framework-internal symbol). | |
| template<class Container, class Elem, class Cls> | |
| static void | _array_interface (Cls &cls) |
| Give the opaque std::vector<Elem> class cls a __array_interface__ property — the numpy array-interface dict (numpy.asarray(v) reads it), a structured, zero-copy, writable view of data(), numpy-free (a plain Python attribute); the field descr is reflected from Elem's POD layout (welder::rods::python::ai_descr). | |
| static void | close_module (module_type &m, nb::dict &live) |
| Close the session: apply any accumulated live properties. | |
Static Public Attributes | |
| static constexpr lang | language {lang::py} |
| welder::lang::py. | |
| template<class T> | |
| static constexpr bool | has_native_caster = !_needs_registration<T> |
| caster_oracle: T is convertible without welder registering a class for it iff nanobind does not fall back to runtime class registration. | |
| template<std::meta::info Mem, class Bound> | |
| static constexpr bool | _erasable_field |
| Whether Mem can bind through the class-ERASED field path (see _def_erased_field): a public, non-bit-field member declared DIRECTLY in bound class Bound, of a type nanobind converts to an IMMUTABLE Python object (arithmetic, enum, or std::string — where by-value vs by-reference at the C++ boundary is unobservable and the caster is the same either way). | |
Protected Types | |
| template<class T, std::size_t I> | |
| using | _init_param |
| The synthesized field constructor's parameter type for field I of T: the field type itself, or std::optional of it for a lazy default (see _lazy_default). | |
Static Protected Member Functions | |
| static consteval nb::rv_policy | _rv_policy (::welder::rv_kind k) |
| Map welder's neutral welder::rv_kind to nanobind's rv_policy. | |
| template<std::meta::info Fn, class Style> | |
| static consteval auto | _styled_param_names () |
| Register the function/method reflected by Fn onto a nanobind target. | |
| template<std::meta::info Fn, class Style, class Def, std::size_t... I, std::size_t... K> | |
| static void | _def_function (const char *name, Def def_into, std::index_sequence< I... >, std::index_sequence< K... >) |
| template<std::meta::info Fn, class Self, class Style, class Def, std::size_t... I> | |
| static void | _def_truncated (const char *name, Def def_into, std::index_sequence< I... >) |
| Bind ONE truncated overload of Fn taking its first sizeof...(I) parameters: the wrapper calls the C++ function with that many arguments and the LANGUAGE applies the real default(s) — reflection can see that a default exists but not its value, so re-stating it is impossible and synthesizing the call is the only faithful binding. | |
| template<std::meta::info Fn, class Self, class Style, class Def, std::size_t... K> | |
| static void | _def_default_truncations (const char *name, Def def_into, std::index_sequence< K... >) |
| Bind every omissible arity of Fn (one per trailing defaulted parameter): arities P-D .
| |
| template<std::meta::info Fn, class Style, class Def> | |
| static void | _def_function (const char *name, Def def_into) |
| Convenience overload: derive the parameter and keep_alive index sequences from Fn. | |
| template<std::meta::info Ctor, std::size_t D, class Style, std::size_t... K> | |
| static void | _def_init_truncations (auto &cls, std::index_sequence< K... >) |
| Register nb::init<P0, P1, …>() for constructor Ctor. | |
| template<std::meta::info Ctor, class Style, std::size_t... I> | |
| static void | _def_init (auto &cls, std::index_sequence< I... >) |
| template<class T> | |
| static nb::object | _copy_instance (nb::handle self, nb::object *memo) |
| The subclass-faithful engine behind __copy__/__deepcopy__. | |
| template<class T, std::size_t I> | |
| static consteval bool | _lazy_default () |
| Whether field I of aggregate T binds its NSDMI default LAZILY: true for a defaultable field whose type needs class/enum registration. | |
| template<class T, std::size_t I> | |
| static auto | _init_value (_init_param< T, I > &&arg) |
| The value brace-initializing field I of T from constructor argument arg: the argument itself for a plain parameter; for a lazy-default optional, the engaged value or — when disengaged — the field's NSDMI value read off a fresh T{}. | |
| template<class T, std::size_t I, class Style> | |
| static auto | _aggregate_arg (const T &probe) |
| The nb::arg for field I of aggregate T: named after the field and, for the defaultable NSDMI suffix (see welder::detail::aggregate_defaults_from), carrying the field's NSDMI value — read off the value-initialized probe — as a real keyword default, so Python may omit it or skip past it by keyword. | |
| template<class T, class Style, std::size_t... I> | |
| static void | _def_aggregate_init (auto &cls, std::index_sequence< I... >) |
| Synthesize a field constructor for a baseless aggregate T. | |
| static void | _install_live_properties (nb::module_ &m, nb::dict props) |
| Give module m live get/set semantics for the names in props. | |
| template<class T, class Trampoline, auto Bases, std::size_t... I> | |
| static auto | _make_class (nb::handle scope, const char *name, const char *doc, std::index_sequence< I... >) |
| Construct nb::class_<T, NativeBases...> from a reflected base-type array. | |
| template<class T, auto Bases, std::size_t... I> | |
| static auto | _make_class_at (nb::handle scope, const char *name, const char *doc, std::index_sequence< I... > seq) |
| The trampoline-aware class factory over an arbitrary registration scope — the shared body of make_class (scope = the module) and make_nested_class (scope = the enclosing class handle). | |
Static Protected Attributes | |
| template<class T> | |
| static constexpr bool | _needs_registration |
| Whether nanobind can only convert T via runtime class registration. | |
Static Private Member Functions | |
| template<std::meta::info Fn, bool NotImpl, class Cls, std::size_t... K> | |
| static void | _def_operator (const char *name, Cls &cls, std::index_sequence< K... >) |
| Def operator Fn (member, or free with the anchor on the left) under dunder name. | |
| template<class T, std::meta::info Fn> | |
| static void | _def_reflected_operator (auto &cls) |
| Bind reflected free operator Fn (T is its right operand) under its reflected dunder, swapping the operands back into declaration order for the C++ call. | |
The nanobind rod: a stateless policy type satisfying welder::rod.
Its public static members are the nanobind emission primitives welder's driver calls; the driver supplies all the reflection-derived decisions. Each implements the correspondingly-named hook of the welder::rod contract (and welder::caster_oracle) — every one carries a @see back to it, where the shared parameter and return-value semantics are documented once rather than repeated on each backend's mirror. The protected members below are nanobind-specific implementation helpers (prefixed _), not part of the contract.
| DocStyle | the docstring convention this rod folds function/parameter/ return docs into (a welder::doc_style). Defaults to welder::rods::python::google_style; pass welder::rods::python::numpy_style or welder::rods::python::sphinx_style to emit those dialects. Defaulted, so rod<> is the Google-style rod and code that wants a different dialect names rod<numpy_style>. |
|
protected |
The synthesized field constructor's parameter type for field I of T: the field type itself, or std::optional of it for a lazy default (see _lazy_default).
| using welder::rods::nanobind::rod< DocStyle >::class_handle_type |
The class handle make_class yields for T — exactly its return type for a base-less T (so it captures the woven-in trampoline for a virtual T); the single welded base nanobind supports is chosen by the carriage's resolution, not by T, so it is appended by make_class and is not a function of T alone.
Named as an associated type so the welder::rod concept can shape-check the per-class hooks against it.
| using welder::rods::nanobind::rod< DocStyle >::construction_type |
The type welder constructs when binding T — its registered trampoline if one exists, else T — so an abstract base with a trampoline stays constructible from a Python subclass.
The driver reads this to decide default constructibility.
| using welder::rods::nanobind::rod< DocStyle >::enum_handle_type = nb::enum_<E> |
The enum handle make_enum yields — exactly its return type.
(The class handle class_handle_type is defined next to make_class below, since it tracks that function's return.) Named as an associated type so the welder::rod concept can shape-check the per-enum hooks against it.
| using welder::rods::nanobind::rod< DocStyle >::module_type = nb::module_ |
|
inlinestaticprotected |
The nb::arg for field I of aggregate T: named after the field and, for the defaultable NSDMI suffix (see welder::detail::aggregate_defaults_from), carrying the field's NSDMI value — read off the value-initialized probe — as a real keyword default, so Python may omit it or skip past it by keyword.
A LAZY default (registration-needed type, _lazy_default) binds = None with an ... signature instead — no Python default object exists, the C++ side materializes the NSDMI value.
| T | the aggregate type. |
| I | the field index. |
| probe | a value-initialized instance supplying the default values (unused for a required or lazy-default field). |
Definition at line 446 of file rod.hpp.
References _lazy_default(), welder::detail::aggregate_defaults_from(), welder::detail::aggregate_fields(), welder::field, language, and welder::name_of().
Referenced by _def_aggregate_init().
|
inlinestatic |
Give the opaque std::vector<Elem> class cls a __array_interface__ property — the numpy array-interface dict (numpy.asarray(v) reads it), a structured, zero-copy, writable view of data(), numpy-free (a plain Python attribute); the field descr is reflected from Elem's POD layout (welder::rods::python::ai_descr).
Definition at line 1434 of file rod.hpp.
Referenced by _numpy_view().
|
inlinestatic |
Bind fixed-size sequence Container (std::array<T, N>) opaquely — by reference, with element write-through — under name.
Neither framework ships a bind_array, so this hand-writes the bind_vector surface minus the size-changing ops: __len__ (the constant N), __getitem__ / __setitem__ (a welded-class element handed out as a live reference_internal alias so a[i].field = x writes through; a scalar returned by value), __iter__, and the same zero-copy NumPy view as a scalar/ POD vector (_numpy_view). There is deliberately no append/insert/ pop/extend/clear (a fixed array cannot resize). Whole-attribute assignment from a length-N sequence still works: a __init__ from any iterable (length checked — a wrong length raises ValueError) is registered as an implicit conversion, so obj.arr = [...] rebinds through def_rw. A length-changing slice assignment is rejected — only integer indices are bound, so a slice subscript raises TypeError.
Definition at line 1331 of file rod.hpp.
References _numpy_view(), and _wrap_index().
Referenced by bind_container().
|
inlinestaticprotected |
The subclass-faithful engine behind __copy__/__deepcopy__.
Mirrors what Python's own copy machinery does for a pure-Python object — state transfer, never __init__: an uninitialized shell of the instance's dynamic type (type(self).__new__(type(self)), so a Python subclass copies as itself), the C++ payload copy-constructed in place on the shell (for a Python-derived shell the alias (trampoline) payload — which is why the trampoline needs a copy-from-base constructor — so the copy keeps dispatching virtuals into Python), then the instance __dict__ carried over. With memo (the __deepcopy__ path) the fresh object is recorded under id(self) before the __dict__ is deep-copied through it, so shared references dedup and reference cycles terminate, exactly per the copy module's contract. __slots__-declared state carries over too: slot names are collected by copyreg._slotnames — the stdlib's own MRO-walking collector (what pickle uses), private-name mangling included — so a subclass keeping its state out of __dict__ still copies whole.
| T | the registered type. |
| self | the instance being copied (possibly of a Python subclass). |
| memo | the __deepcopy__ memo dict, or nullptr for __copy__. |
Definition at line 343 of file rod.hpp.
Referenced by add_constructors().
|
inlinestaticprotected |
Synthesize a field constructor for a baseless aggregate T.
nanobind builds a custom constructor by binding an __init__ whose first parameter is a pointer to the (uninitialized) instance; the body placement-news the aggregate and assigns the provided field values. Fields in the NSDMI suffix become keyword parameters with real defaults (_aggregate_arg) — except registration-needed ones, which bind Optional[F] = None and default in C++ (_lazy_default), so no bound-class instance ever lives in the function record.
| T | the aggregate type. |
| I | the field index pack. |
| cls | the class handle. |
Definition at line 476 of file rod.hpp.
References _aggregate_arg(), _init_value(), welder::detail::aggregate_defaults_from(), welder::detail::aggregate_fields(), welder::field, language, and welder::name_of().
Referenced by add_constructors().
|
inlinestaticprotected |
Bind every omissible arity of Fn (one per trailing defaulted parameter): arities P-D .
. P-1, the full-arity def having been bound by _def_function already.
Definition at line 269 of file rod.hpp.
References _def_truncated().
Referenced by add_function(), add_method(), and add_static_method().
|
inlinestatic |
Bind one field as a property through CLASS-ERASED accessors: the closures capture the member's byte offset as runtime state and take nb::handle self, so their closure TYPE — and therefore nanobind's func_create instantiation — depends only on the field type D.
One instantiation per field type serves every welded class in the module, where def_rw instantiates per (class, field type): on a surface of ~4200 generated record classes that difference was the single largest code bucket in the binding shards.
Installed through nanobind's type-erased property_install, NOT class_<T>::def_prop_rw — the latter is a member of class_<T> and would reintroduce the class dimension this path exists to remove.
Why this is not UB, precisely:
Definition at line 810 of file rod.hpp.
References welder::doc().
Referenced by add_field().
|
inlinestaticprotected |
Convenience overload: derive the parameter and keep_alive index sequences from Fn.
Definition at line 281 of file rod.hpp.
References _def_function(), and welder::detail::keep_alive_pairs().
|
inlinestaticprotected |
Definition at line 197 of file rod.hpp.
References _rv_policy(), _styled_param_names(), welder::detail::all_params_named(), welder::doc(), welder::function_docstring(), welder::detail::keep_alive_pairs(), language, welder::return_policy_of(), and welder::validate_return_policy().
Referenced by _def_function(), add_function(), add_method(), and add_static_method().
|
inlinestaticprotected |
Definition at line 311 of file rod.hpp.
References _styled_param_names(), welder::detail::all_params_named(), and welder::detail::param_types().
Referenced by _def_init_truncations(), and add_constructors().
|
inlinestaticprotected |
Register nb::init<P0, P1, …>() for constructor Ctor.
Names the parameters (nb::arg) when all are named, otherwise positional.
| Ctor | a reflection of the constructor. |
| I | the parameter index pack. |
| cls | the class handle. Bind every omissible arity of constructor Ctor (arities P-D .. P-1): _def_init already takes the parameter index sequence, so each omissible arity is just a shorter one — the init calls the constructor with fewer arguments and the LANGUAGE applies the real defaults. A named template (not an immediately-invoked lambda): a lambda whose body touches std::meta::parameters_of is escalated to an immediate function, and the runtime _def_init call inside would then be ill-formed. |
Definition at line 305 of file rod.hpp.
References _def_init().
Referenced by add_constructors().
|
inlinestaticprivate |
Def operator Fn (member, or free with the anchor on the left) under dunder name.
Unlike _def_function, never passes nb::arg names — Python's operator protocol is positional-only. Docstring, return_policy and keep_alives ride along as usual; NotImpl appends nb::is_operator() (see add_operator).
| Fn | the operator. |
| K | the keep_alive index pack. |
Definition at line 1056 of file rod.hpp.
References _rv_policy(), welder::doc(), welder::function_docstring(), welder::detail::keep_alive_pairs(), language, welder::return_policy_of(), and welder::validate_return_policy().
Referenced by add_operator().
|
inlinestaticprivate |
Bind reflected free operator Fn (T is its right operand) under its reflected dunder, swapping the operands back into declaration order for the C++ call.
| T | the anchor type. |
| Fn | the operator. |
Definition at line 1083 of file rod.hpp.
References welder::rods::python::reflected_dunder(), and welder::validate_return_policy().
Referenced by add_operator().
|
inlinestaticprotected |
Bind ONE truncated overload of Fn taking its first sizeof...(I) parameters: the wrapper calls the C++ function with that many arguments and the LANGUAGE applies the real default(s) — reflection can see that a default exists but not its value, so re-stating it is impossible and synthesizing the call is the only faithful binding.
Self is the BOUND class for a nonstatic member (the wrapper takes Self& and calls through the object, so members flattened from bases resolve by ordinary lookup), or void for free/static functions.
The truncated defs carry the argument names (kwargs keep working) and the return policy; the docstring stays on the full-arity def only, and keep_alive annotations are deliberately not repeated — an omitted argument cannot nurse anything, and the full overload still carries them for explicit calls.
Definition at line 236 of file rod.hpp.
References _rv_policy(), _styled_param_names(), welder::detail::all_params_named(), language, welder::detail::param_types(), and welder::return_policy_of().
Referenced by _def_default_truncations().
|
inlinestaticprotected |
The value brace-initializing field I of T from constructor argument arg: the argument itself for a plain parameter; for a lazy-default optional, the engaged value or — when disengaged — the field's NSDMI value read off a fresh T{}.
Yielding VALUES (rather than assigning into an NSDMI-initialized instance) keeps aggregate semantics intact for const-qualified members.
Definition at line 421 of file rod.hpp.
References _lazy_default(), welder::detail::aggregate_fields(), and welder::field.
Referenced by _def_aggregate_init().
|
inlinestaticprotected |
Give module m live get/set semantics for the names in props.
Reassigns m's Python class to a fresh subclass of its current class carrying props (name → property). Python modules don't support properties directly, but a module's __class__ may be swapped for a ModuleType subclass. Used only when a (sub)module exposes a mutable variable.
Subclassing the module's current class — rather than ModuleType outright — means repeated installs onto the same handle accumulate: welding a standalone variable and then a whole namespace onto the same module each add a layer, and the earlier properties survive in the MRO instead of being clobbered.
| m | the module handle. |
| props | a dict of name → property. |
Definition at line 515 of file rod.hpp.
Referenced by close_module().
|
inlinestaticconstevalprotected |
Whether field I of aggregate T binds its NSDMI default LAZILY: true for a defaultable field whose type needs class/enum registration.
Such a default must NOT live in the function record as a Python object — a bound-class default holds its type through an edge the garbage collector cannot traverse (a plain nanobind instance is not a GC object, so its implicit type reference is invisible), and CHAINS of such defaults (Sequence{Bounds{Box{Vector}}}) become uncollectable cycles that nanobind reports as leaked types/instances at interpreter shutdown (see nanobind's refleaks documentation). The synthesized constructor takes std::optional<F> = None instead and materializes the NSDMI value in C++ when the argument is omitted.
Definition at line 393 of file rod.hpp.
References welder::detail::aggregate_defaults_from(), welder::detail::aggregate_fields(), and has_native_caster.
Referenced by _aggregate_arg(), and _init_value().
|
inlinestaticprotected |
Construct nb::class_<T, NativeBases...> from a reflected base-type array.
A non-null doc becomes the class docstring (nanobind treats a bare const char* extra as the doc); nullptr is branched out rather than passed.
| T | the class type. |
| Bases | the static array of native base type reflections. |
| I | the base index pack. |
| scope | the registration scope — the module, or (for a nested type) the enclosing class handle; nanobind accepts any handle. |
| name | the Python class name. |
| doc | the class docstring, or nullptr. |
Definition at line 544 of file rod.hpp.
References welder::doc().
Referenced by _make_class_at().
|
inlinestaticprotected |
The trampoline-aware class factory over an arbitrary registration scope — the shared body of make_class (scope = the module) and make_nested_class (scope = the enclosing class handle).
Coverage / bind_flat gating as documented on make_class.
Definition at line 565 of file rod.hpp.
References _make_class(), welder::bound_flat(), welder::doc(), welder::has_virtual_methods(), and welder::py.
Referenced by make_class(), and make_nested_class().
|
inlinestatic |
Give contiguous sequence class cls the zero-copy NumPy view its element type supports: an __array__ returning a live nb::ndarray for an arithmetic (non-bool) element, or the structured __array_interface__ dict for a POD struct element (_array_interface).
A non-contiguous / non-viewable element gets neither. Shared by the std::vector and std::array paths (both expose .data()/.size()).
| Container | the contiguous sequence. |
Definition at line 1393 of file rod.hpp.
References _array_interface(), welder::container_is_contiguous(), and welder::rods::python::pod_array_eligible().
Referenced by _bind_array(), and bind_container().
|
inlinestaticconstevalprotected |
Map welder's neutral welder::rv_kind to nanobind's rv_policy.
nanobind carries the full set, none included, so every kind maps.
| k | the neutral policy. |
Definition at line 146 of file rod.hpp.
Referenced by _def_function(), _def_operator(), _def_truncated(), and add_property().
|
inlinestaticconstevalprotected |
Register the function/method reflected by Fn onto a nanobind target.
The folded docstring is passed when non-empty, and nb::arg(name)... when every parameter is named (so Python callers see real keyword arguments, not positional-only). Two call policies ride along as trailing .def extras: the [[=welder::return_policy]] (mapped to rv_policy, always passed — automatic is nanobind's default, so an unannotated call is unchanged) and each [[=welder::keep_alive]] (spliced as nb::keep_alive<nurse, patient>()). A reference-category policy on a by-value return is rejected first (welder::validate_return_policy).
| Fn | a reflection of the function. |
| Def | the target-adapter callable type. |
| I | the parameter index pack. |
| K | the keep_alive-dependency index pack. |
| name | the Python name. |
| def_into | adapts the target — cls.def, cls.def_static, or m.def. The styled kwarg names of Fn's parameters: each named parameter's identifier reshaped through the style's FIELD hook — a keyword argument is attribute-shaped in the target language, so it follows the same convention as data members (clientPath C++ ⇒ client_path kwarg under a snake_case style). Unnamed parameters stay null. |
| Fn | a reflection of the callable. |
Definition at line 185 of file rod.hpp.
Referenced by _def_function(), _def_init(), and _def_truncated().
|
inlinestatic |
Normalize a Python index i (allowing one level of negative wrap-around) against length n, raising IndexError when out of range — the fixed-array __getitem__/__setitem__ bounds check (the bind_vector wrap analogue, reproduced here so the array path does not lean on a framework-internal symbol).
Definition at line 1420 of file rod.hpp.
Referenced by _bind_array().
|
inlinestatic |
Synthesize the relational dunders from operator<=> group Fns via rewritten expressions (a < b, …), skipping the slots an explicit participating operator already Covered — the same semantics as the pybind11 rod (the shared walk is welder::rods::python::synthesize_comparisons).
Definition at line 1034 of file rod.hpp.
References welder::rods::python::synthesize_comparisons().
|
inlinestatic |
Bind T's whole constructor set (a chained-def framework just loops it): the default constructor when HasDefault, an nb::init<…> per member of Ctors, and the synthesized aggregate field constructor when Aggregate.
Copyable (the carriage-admitted copy constructor) becomes the copy protocol alone — __copy__ and __deepcopy__(memo), both subclass-faithful** via _copy_instance — a Python subclass instance copies as its own type, __dict__ and virtual dispatch intact, with the C++ payload duplicated by the copy constructor (whose deep/shallow distinction is its own: value members duplicate, a pointer member copies as a pointer). It is deliberately NOT exposed as a T(other) init overload: that C++-ism is unidiomatic in Python (copying goes through the copy module) and would clash with a one-arg user constructor. The memo parameter is typed object, not dict — a bare dict in the generated stub fails strict mypy (disallow_any_generics).
Definition at line 707 of file rod.hpp.
References _copy_instance(), _def_aggregate_init(), _def_init(), _def_init_truncations(), welder::detail::aggregate_fields(), and welder::detail::trailing_default_count().
|
inlinestatic |
Add enumerator Enum to the enum handle.
Definition at line 1138 of file rod.hpp.
References welder::name_of().
|
inlinestatic |
Bind data member Mem as an attribute.
nanobind data members become Python properties (data descriptors on the class), so a [[=welder::doc]] on the member rides along as the property's __doc__ — and thus reaches .pyi stubs. A const member — or one marked [[=welder::mark::no_reassign]] — is read-only (def_ro); an otherwise-mutable member is read/write (def_rw). The doc, when present, is passed as the property docstring. There is deliberately no setter docstring: a Python property surfaces only the getter's __doc__.
A directly-declared member of immutable-converting type binds through the class-erased path (_def_erased_field) — observably identical, one template instantiation per field TYPE instead of per (class, field type). Everything else takes the member-pointer path below.
Definition at line 849 of file rod.hpp.
References _def_erased_field(), _erasable_field, welder::doc(), welder::doc_of(), language, welder::member_no_reassign(), and welder::name_of().
|
inlinestatic |
Bind free-function overload group Fns as one module-level function (name from Fns[0]; one chained .def per overload).
A non-null name overrides the resolved name (including any weld_as), used verbatim; nullptr falls back to the styled/weld_as name.
Definition at line 1178 of file rod.hpp.
References _def_default_truncations(), _def_function(), welder::function, language, welder::name_of_or(), and welder::detail::trailing_default_count().
|
inlinestatic |
Bind method overload group Fns (name from Fns[0]; nanobind chains one .def per overload and dispatches at call time).
Definition at line 961 of file rod.hpp.
References _def_default_truncations(), _def_function(), welder::name_of(), and welder::detail::trailing_default_count().
|
inlinestatic |
Bind operator slot group Fns — one (operator, arity) slot whole, member and anchored free entries mixed.
A member (or T-on-the-left free) entry binds under the slot's dunder; a free entry with T as the RIGHT operand binds under the REFLECTED dunder (__rmul__, or the mirrored comparison) through an operand-swapping wrapper. Binary arithmetic/comparison defs carry nb::is_operator(): a failed operand conversion returns NotImplemented (Python then tries the other operand's reflected method) instead of raising TypeError.
Definition at line 1014 of file rod.hpp.
References _def_operator(), _def_reflected_operator(), welder::rods::python::dunder_uses_not_implemented(), welder::detail::free_operator_reflected(), welder::detail::keep_alive_pairs(), and welder::rods::python::operator_dunder().
|
inlinestatic |
Bind the resolved property (Getter + optional Setter) as a Python property named name (driver-resolved).
def_prop_rw / def_prop_ro over the spliced member pointers; the getter's [[=welder::doc]] becomes the property __doc__ (only the getter's doc surfaces on a Python property — the add_field rationale). A [[=welder::return_policy]] on the getter is honored; unannotated, a reference/pointer-returning getter gets an explicit reference_internal (nanobind, unlike pybind11, does not default property getters to it — this matches def_rw and the pybind11 rod), while a by-value getter keeps nanobind's automatic (a move — an explicit reference policy there would dangle).
Definition at line 916 of file rod.hpp.
References _rv_policy(), welder::automatic, welder::doc(), welder::doc_of(), language, welder::return_policy_of(), and welder::validate_return_policy().
|
inlinestatic |
Bind static-method overload group Fns.
Definition at line 985 of file rod.hpp.
References _def_default_truncations(), _def_function(), language, welder::name_of(), welder::static_method, and welder::detail::trailing_default_count().
|
inlinestatic |
Bind the swept free ostream inserter Fn as __str__ (via welder::detail::stringify).
Definition at line 1044 of file rod.hpp.
References welder::detail::stringify().
|
inlinestatic |
|
inlinestatic |
Bind namespace variable Var as a module attribute.
A const/constexpr variable becomes a value snapshot; a mutable one becomes a live get/set property over the C++ global (accumulated in live). A non-null name_override is used verbatim (beating any weld_as); nullptr falls back to the styled/weld_as name.
Definition at line 1202 of file rod.hpp.
References welder::name_of_or().
|
inlinestatic |
Bind STL Container opaquely — by reference, with live mutation — under name, the driver's route for a welded container alias (see <welder/containers.hpp>).
A sequence (std::vector/std::deque) becomes an nb::bind_vector class: append (=push_back), __getitem__/__setitem__, slicing, __len__, __iter__ — mutation writes through to the C++ object (a def_rw member of it hands out a live reference). For a welded-class element, __getitem__ / __iter__ themselves hand out a live reference aliasing the C++ element (rv_policy::reference_internal, kept alive to the container), so v[i].field = x writes through; a scalar element is returned by value (a copy). nanobind has no buffer protocol, so for a scalar** element type (arithmetic, not bool) the class gains an __array__ returning an nb::ndarray zero-copy view of data() (kept alive to the container), so numpy.asarray(v) sees the live buffer. A map (std::map/std::unordered_map) becomes an nb::bind_map class whose __getitem__ likewise hands out a live reference to the mapped value.
The container must be declared opaque (WELDER_OPAQUE(Container)) at namespace scope — nanobind otherwise hard-errors when the stl caster for it is also visible (or silently copy-converts it).
Definition at line 1249 of file rod.hpp.
References _bind_array(), _numpy_view(), welder::container_kind_of(), welder::fixed_sequence, and welder::sequence.
|
inlinestatic |
Close the session: apply any accumulated live properties.
Definition at line 1453 of file rod.hpp.
References _install_live_properties().
|
inlinestatic |
Finalize enum E: export an unscoped enum's values into the enclosing scope.
|
inlinestatic |
Create the nb::class_<T, Bases…> handle, weaving in a trampoline when T is a welded virtual type with a registered welder::rods::python::trampoline_for.
A type carrying virtual methods is bound overridable — it must register a trampoline (so Python subclasses can override those virtuals) or opt out with [[=welder::bind_flat]]. When a trampoline is present, its coverage of T's virtuals is checked at compile time.
Definition at line 639 of file rod.hpp.
References _make_class_at(), and welder::doc().
|
inlinestatic |
Create the nb::enum_<E> handle (a non-null doc becomes its docstring).
nb::is_arithmetic() makes it a Python enum.IntEnum, so enumerators are int-convertible (int(E.Value)) and compare against ints — matching the pybind11 backend, whose py::native_enum also binds an enum.IntEnum.
Definition at line 1109 of file rod.hpp.
References welder::doc().
|
inlinestatic |
Create the nb::class_ for a nested member type T, registered under its enclosing type's class handle rather than the module — Python then sees it as module.Outer.Inner (and __qualname__ nests), exactly like a hand-written nb::class_<Outer::Inner>(outer_cls, "Inner").
Same trampoline weaving as make_class.
Definition at line 650 of file rod.hpp.
References _make_class_at(), and welder::doc().
|
inlinestatic |
Create the nb::enum_<E> for a nested member enum, scoped to its enclosing type's class handle — Python sees module.Outer.Mode, and an unscoped* nested enum's export_values() lands its enumerators on the class (mirroring C++'s Outer::red).
ed folds in as for make_enum.
Definition at line 1128 of file rod.hpp.
References welder::doc().
|
inlinestatic |
Open a per-module session: a dict accumulating live (mutable-variable) properties; _install_live_properties() applies them in one __class__ swap at close.
|
inlinestatic |
Retrieve the ALREADY-registered class T as a fillable handle — the two-phase binding hook (optional; declaring it opts the rod into the driver's two-phase namespace sweep).
The name-pre-registration phase creates the nb::class_<T,…> (so scope.attr(name) is it); nb::borrow re-wraps that object as the same handle type make_class yields, so subsequent add_* calls target the same registered type. This lets the driver register every type's NAME (and the opaque containers using them) BEFORE filling any member, so a container-typed member/signature never spells a raw C++ name in a docstring/stub.
|
inlinestatic |
The nested-scope form of reopen_class — retrieve T from its enclosing type's class handle (outer.attr(name)).
|
inlinestatic |
Set the (sub)module docstring.
nanobind's module_ exposes no doc() setter, so the docstring is written straight to the module's __doc__ attribute.
Definition at line 1166 of file rod.hpp.
References welder::doc().
|
inlinestaticconsteval |
Map a member operator to its Python dunder (nullptr = not exposed).
|
staticconstexpr |
Whether Mem can bind through the class-ERASED field path (see _def_erased_field): a public, non-bit-field member declared DIRECTLY in bound class Bound, of a type nanobind converts to an IMMUTABLE Python object (arithmetic, enum, or std::string — where by-value vs by-reference at the C++ boundary is unobservable and the caster is the same either way).
The direct-declaration gate is a correctness gate, not a heuristic: the erased accessors add offset_of(Mem) — an offset relative to the DECLARING class — to the raw instance pointer. For a member flattened in from a base, the base-subobject conversion belongs to the language (self.*p on the member-pointer path), so those members keep it.
Definition at line 767 of file rod.hpp.
Referenced by add_field().
|
staticconstexprprotected |
Whether nanobind can only convert T via runtime class registration.
True iff T's caster is (or derives from) nanobind's generic type_caster_base fallback, which looks T up in nanobind's registered-types map (is_base_caster_v is nanobind's own name for "this caster derives from `type_caster_base`"). True for program-defined classes and enums; false for scalars, strings and the nanobind wrapper types (nb::object, nb::dict, …). This is the one bindability fact welder's core cannot know on its own; it drives has_native_caster below.
Like the pybind11 backend's counterpart, it is conservative — it reads T's caster type at compile time, so it reports whether T needs a class/enum, never whether one exists at runtime, and "native" is relative to the TU's includes (std::string / std::vector / … are native only when their <nanobind/stl/…> converter header is included). A type hand-registered out-of-band still reads true; that false positive is resolved by the deferred trust_bindable escape hatch.
Enums are forced into the needs-registration bucket**: nanobind's dedicated enum caster is not the base caster, but it converts only once the enum is registered (nb::enum_) — an unregistered enum fails at call time. Forcing it keeps welder's gate honest (a welded enum's registration is required) and matches every other rod.
| T | the type whose caster to classify. |
|
staticconstexpr |
caster_oracle: T is convertible without welder registering a class for it iff nanobind does not fall back to runtime class registration.
| T | the type to classify. |
Definition at line 611 of file rod.hpp.
Referenced by _lazy_default().
|
staticconstexpr |
Definition at line 98 of file rod.hpp.
Referenced by _aggregate_arg(), _def_aggregate_init(), _def_function(), _def_operator(), _def_truncated(), add_field(), add_function(), add_property(), and add_static_method().