|
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, auto Ctors, bool HasDefault, bool Aggregate> | |
| static void | add_constructors (auto &cls) |
| Bind the default constructor. | |
| template<std::meta::info Mem, class Style = ::welder::naming::none> | |
| static void | add_field (auto &cls) |
| Bind data member Mem as an attribute. | |
| 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<auto Fns> | |
| static void | add_operator (auto &cls) |
| Bind operator overload group Fns under its Python dunder (one operator + arity per group, so Fns[0] names the slot). | |
| template<class E> | |
| static auto | make_enum (module_type &m, const char *name, const char *doc) |
| 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 char *doc) |
| 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. | |
| 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. | |
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 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... >) |
| Register the function/method reflected by Fn onto a nanobind target. | |
| template<std::meta::info Fn, 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... I> | |
| static void | _def_init (auto &cls, std::index_sequence< I... >) |
| Register nb::init<P0, P1, …>() for constructor Ctor. | |
| template<class T, 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. | |
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>. |
| 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 |
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 from the field values. Emits def("__init__", [](T* self, F0 f0, …) { new (self) T{f0, …}; }, nb::arg("f0"), …) so Python can build it from field values (T(f0, f1)).
| T | the aggregate type. |
| I | the field index pack. |
| cls | the class handle. |
Definition at line 222 of file rod.hpp.
References welder::detail::aggregate_fields().
Referenced by add_constructors().
|
inlinestaticprotected |
Convenience overload: derive the parameter and keep_alive index sequences from Fn.
Definition at line 185 of file rod.hpp.
References _def_function(), and welder::detail::keep_alive_pairs().
|
inlinestaticprotected |
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. |
Definition at line 158 of file rod.hpp.
References _rv_policy(), welder::detail::all_params_named(), welder::doc(), welder::function_docstring(), welder::detail::keep_alive_pairs(), language, welder::detail::param_names(), welder::return_policy_of(), and welder::validate_return_policy().
Referenced by _def_function(), add_function(), add_method(), add_operator(), and add_static_method().
|
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. |
Definition at line 201 of file rod.hpp.
References welder::detail::all_params_named(), welder::detail::param_names(), and welder::detail::param_types().
Referenced by add_constructors().
|
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 247 of file rod.hpp.
Referenced by close_module().
|
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 276 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 297 of file rod.hpp.
References _make_class(), welder::doc(), and welder::py.
Referenced by make_class(), and make_nested_class().
|
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 126 of file rod.hpp.
Referenced by _def_function().
|
inlinestatic |
Bind the default constructor.
Definition at line 403 of file rod.hpp.
References _def_aggregate_init(), _def_init(), and welder::detail::aggregate_fields().
|
inlinestatic |
Add enumerator Enum to the enum handle.
Definition at line 534 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 is read-only (def_ro); a mutable one 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__.
Definition at line 426 of file rod.hpp.
References welder::doc(), welder::doc_of(), 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 574 of file rod.hpp.
References _def_function(), welder::function, language, and welder::name_of_or().
|
inlinestatic |
Bind method overload group Fns (name from Fns[0]; nanobind chains one .def per overload and dispatches at call time).
Definition at line 468 of file rod.hpp.
References _def_function(), and welder::name_of().
|
inlinestatic |
Bind operator overload group Fns under its Python dunder (one operator + arity per group, so Fns[0] names the slot).
Definition at line 494 of file rod.hpp.
References _def_function(), and welder::rods::python::operator_dunder().
|
inlinestatic |
Bind static-method overload group Fns.
Definition at line 480 of file rod.hpp.
References _def_function(), language, welder::name_of(), and welder::static_method.
|
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 592 of file rod.hpp.
References welder::name_of_or().
|
inlinestatic |
Close the session: apply any accumulated live properties.
Definition at line 618 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::rods::python::bind_flat]]. When a trampoline is present, its coverage of T's virtuals is checked at compile time.
Definition at line 371 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 512 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 382 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).
Definition at line 525 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 |
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 562 of file rod.hpp.
References welder::doc().
|
inlinestaticconsteval |
Map a member operator to its Python dunder (nullptr = not exposed).
|
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. |
|
staticconstexpr |
Definition at line 78 of file rod.hpp.
Referenced by _def_function(), add_function(), and add_static_method().