welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
rod.hpp
Go to the documentation of this file.
1#pragma once
27#include <array>
28#include <cstddef>
29#include <memory>
30#include <meta>
31#include <string>
32#include <type_traits>
33#include <utility>
34
35#include <welder/welder.hpp> // welder::welder + the rod contract + driver
36#include <welder/rods/python/doc_style.hpp> // welder::rods::python::google_style
37#include <welder/rods/python/operators.hpp> // welder::rods::python::operator_dunder
38#include <welder/rods/python/trampoline.hpp> // trampoline_for / gate / coverage
39#include <welder/bind_traits.hpp>// param_types / param_names / aggregate_fields
40#include <welder/doc.hpp> // function_docstring
41
42#include <pybind11/pybind11.h>
43#include <pybind11/native_enum.h> // py::native_enum (stdlib enum binding)
44
45namespace welder::inline v0::rods::pybind11 {
46
47// Inside `welder::rods::pybind11`, the unqualified name `pybind11` resolves to *this*
48// namespace, not the library. Alias the real one once — the way pybind11's own
49// docs spell it — and use `py::` for every library reference below.
50namespace py = ::pybind11;
51
70template <::welder::doc_style DocStyle = ::welder::rods::python::google_style>
71struct rod {
72 static constexpr lang language{lang::py};
73 using module_type = py::module_;
74
75 protected:
76 // --- implementation helpers (not part of the welder::rod contract) --
77
117 template <class T>
118 static constexpr bool _needs_registration =
119 std::is_enum_v<std::remove_cvref_t<T>> ||
120 std::is_base_of_v<py::detail::type_caster_base<py::detail::intrinsic_t<T>>,
121 py::detail::make_caster<T>>;
122
131 static consteval py::return_value_policy _return_value_policy(::welder::rv_kind k) {
132 switch (k) {
133 case ::welder::rv_kind::automatic: return py::return_value_policy::automatic;
134 case ::welder::rv_kind::automatic_reference: return py::return_value_policy::automatic_reference;
135 case ::welder::rv_kind::take_ownership: return py::return_value_policy::take_ownership;
136 case ::welder::rv_kind::copy: return py::return_value_policy::copy;
137 case ::welder::rv_kind::move: return py::return_value_policy::move;
138 case ::welder::rv_kind::reference: return py::return_value_policy::reference;
139 case ::welder::rv_kind::reference_internal: return py::return_value_policy::reference_internal;
140 case ::welder::rv_kind::none: break; // no pybind11 equivalent
141 }
142 return py::return_value_policy::automatic;
143 }
144
162 template <std::meta::info Fn, class Def, std::size_t... I, std::size_t... K>
163 static void _def_function(const char* name, Def def_into,
164 std::index_sequence<I...>, std::index_sequence<K...>) {
165 static constexpr auto names{::welder::detail::param_names<Fn>()};
166 static constexpr auto ka{::welder::detail::keep_alive_pairs<Fn>()};
168 constexpr ::welder::rv_kind rvk{::welder::return_policy_of(Fn, language)};
169 static_assert(rvk != ::welder::rv_kind::none,
170 "welder: return_policy 'none' has no pybind11 equivalent "
171 "(it is nanobind-only) — choose another policy");
172 constexpr py::return_value_policy rvp{_return_value_policy(rvk)};
175 if (doc.empty())
176 def_into(name, &[:Fn:], py::arg(names[I])..., rvp,
177 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
178 else
179 def_into(name, &[:Fn:], doc.c_str(), py::arg(names[I])..., rvp,
180 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
181 } else {
182 if (doc.empty())
183 def_into(name, &[:Fn:], rvp,
184 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
185 else
186 def_into(name, &[:Fn:], doc.c_str(), rvp,
187 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
188 }
189 }
190
193 template <std::meta::info Fn, class Def>
194 static void _def_function(const char* name, Def def_into) {
196 name, def_into,
197 std::make_index_sequence<std::meta::parameters_of(Fn).size()>{},
198 std::make_index_sequence<
200 }
201
209 template <std::meta::info Ctor, std::size_t... I>
210 static void _def_init(auto& cls, std::index_sequence<I...>) {
211 static constexpr auto params{::welder::detail::param_types<Ctor>()};
212 static constexpr auto names{::welder::detail::param_names<Ctor>()};
214 cls.def(py::init<typename [:params[I]:]...>(), py::arg(names[I])...);
215 else
216 cls.def(py::init<typename [:params[I]:]...>());
217 }
218
228 template <class T, std::size_t... I>
229 static void _def_aggregate_init(auto& cls, std::index_sequence<I...>) {
230 static constexpr auto fields{::welder::detail::aggregate_fields<T>()};
231 cls.def(py::init([](typename [:std::meta::type_of(fields[I]):]... args) {
232 return T{std::move(args)...};
233 }),
234 py::arg(std::define_static_string(
235 std::meta::identifier_of(fields[I])))...);
236 }
237
252 static void _install_live_properties(py::module_& m, py::dict props) {
253 auto builtins{py::module_::import("builtins")};
254 auto subclass{builtins.attr("type")(
255 py::str("welder_live_module"),
256 py::make_tuple(m.attr("__class__")), props)};
257 // The dynamically-created class would otherwise carry
258 // `__module__ == "_frozen_importlib"` (the frame that ran module init).
259 // pybind11 copies a module *scope*'s `__module__` onto every function later
260 // defined on it, so any function welded onto `m` after this swap — e.g. a
261 // `weld_function` following a mutable `weld_variable` on the same handle —
262 // would be misattributed in generated stubs. Stamp the module's own name so
263 // those functions keep the right `__module__`.
264 subclass.attr("__module__") = m.attr("__name__");
265 m.attr("__class__") = subclass;
266 }
267
281 template <class T, class Trampoline, auto Bases, std::size_t... I>
282 static auto _make_class(py::handle scope, const char* name, const char* doc,
283 std::index_sequence<I...>) {
284 if constexpr (std::is_void_v<Trampoline>) {
285 if (doc)
286 return py::class_<T, typename [:Bases[I]:]...>(scope, name, doc);
287 return py::class_<T, typename [:Bases[I]:]...>(scope, name);
288 } else {
289 // The trampoline is an extra `py::class_` template argument; Python
290 // subclasses instantiate it, so their overrides capture C++ virtual calls.
291 if (doc)
292 return py::class_<T, Trampoline, typename [:Bases[I]:]...>(scope, name, doc);
293 return py::class_<T, Trampoline, typename [:Bases[I]:]...>(scope, name);
294 }
295 }
296
306 template <class T, auto Bases, std::size_t... I>
307 static auto _make_class_at(py::handle scope, const char* name,
308 const char* doc, std::index_sequence<I...> seq) {
309 namespace py_ = ::welder::rods::python;
310 if constexpr (py_::has_virtual_methods(^^T)) {
311 // Resolve the trampoline: an explicit `trampoline_for<T>` wins; otherwise
312 // scan T's namespace for a `[[=trampoline]]`-annotated subclass.
313 constexpr auto scanned{py_::scanned_trampoline_of(^^T)};
314 static_assert(
315 py_::trampoline_for<T> != std::meta::info{} || !scanned.ambiguous,
316 "welder: more than one [[=welder::rods::python::trampoline]] class in "
317 "this namespace derives from T; disambiguate by specializing "
318 "welder::rods::python::trampoline_for<T>.");
319 constexpr std::meta::info tramp{py_::trampoline_for<T> != std::meta::info{}
320 ? py_::trampoline_for<T>
321 : scanned.type};
322 if constexpr (tramp != std::meta::info{}) {
323 using Trampoline = [:tramp:];
324 static_assert(
325 py_::trampoline_covers(^^T, ^^Trampoline),
326 "welder: the trampoline registered for this type does not "
327 "override all of its virtual methods; every virtual needs an "
328 "override forwarding to Python (see WELDER_PY_OVERRIDE).");
329 return _make_class<T, Trampoline, Bases>(scope, name, doc, seq);
330 } else {
331 static_assert(
332 py_::bound_flat(^^T),
333 "welder: this welded type has virtual methods but no trampoline "
334 "is registered, so a Python subclass could not override them. "
335 "Register one — a [[=welder::rods::python::trampoline]] subclass "
336 "in T's namespace, or a welder::rods::python::trampoline_for<T> "
337 "specialization — or annotate T with "
338 "[[=welder::rods::python::bind_flat]] to bind it non-overridably.");
339 return _make_class<T, void, Bases>(scope, name, doc, seq);
340 }
341 } else {
342 return _make_class<T, void, Bases>(scope, name, doc, seq);
343 }
344 }
345
346 public:
347 // --- caster oracle + emission primitives (the welder::rod contract) --
348
352 template <class T>
354
357 static consteval const char* special_method_name(std::meta::info op_fn) {
358 return ::welder::rods::python::operator_dunder(op_fn);
359 }
360
361 // --- class binding ------------------------------------------------------
362
367 template <class T>
370
380 template <class T, auto Bases, std::size_t... I>
381 static auto make_class(module_type& m, const char* name, const char* doc,
382 std::index_sequence<I...> seq) {
383 return _make_class_at<T, Bases>(m, name, doc, seq);
384 }
385
391 template <class T, auto Bases, std::size_t... I>
392 static auto make_nested_class(module_type&, auto& outer_cls, const char* name,
393 const char* doc, std::index_sequence<I...> seq) {
394 return _make_class_at<T, Bases>(outer_cls, name, doc, seq);
395 }
396
401 template <class T, auto Ctors, bool HasDefault, bool Aggregate>
402 static void add_constructors(auto& cls) {
403 if constexpr (HasDefault)
404 cls.def(py::init<>());
405 template for (constexpr auto ctor : std::define_static_array(Ctors)) {
406 _def_init<ctor>(cls, std::make_index_sequence<
407 std::meta::parameters_of(ctor).size()>{});
408 }
409 if constexpr (Aggregate) {
410 constexpr auto fields{::welder::detail::aggregate_fields<T>()};
411 _def_aggregate_init<T>(cls, std::make_index_sequence<fields.size()>{});
412 }
413 }
414
425 template <std::meta::info Mem, class Style = ::welder::naming::none>
426 static void add_field(auto& cls) {
427 constexpr const char* name{
429 constexpr const char* doc{::welder::doc_of<Mem>()};
430 if constexpr (!std::meta::is_public(Mem)) {
431 // A protected member (admitted under policy::weld_protected) binds
432 // as a property over welder::detail::field_access — gcc-16 rejects
433 // the dependent `&[:Mem:]` for protected data (see field_access).
434 // Same semantics as def_readwrite: reference_internal getter.
436 if constexpr (std::meta::is_const_type(std::meta::type_of(Mem))) {
437 if constexpr (doc)
438 cls.def_property_readonly(
439 name, &fa::get, py::return_value_policy::reference_internal,
440 doc);
441 else
442 cls.def_property_readonly(
443 name, &fa::get,
444 py::return_value_policy::reference_internal);
445 } else {
446 if constexpr (doc)
447 cls.def_property(name, &fa::get, &fa::set,
448 py::return_value_policy::reference_internal,
449 doc);
450 else
451 cls.def_property(name, &fa::get, &fa::set,
452 py::return_value_policy::reference_internal);
453 }
454 } else if constexpr (std::meta::is_const_type(std::meta::type_of(Mem))) {
455 // const member: read-only (def_readwrite's setter would not compile).
456 if constexpr (doc)
457 cls.def_readonly(name, &[:Mem:], doc);
458 else
459 cls.def_readonly(name, &[:Mem:]);
460 } else {
461 if constexpr (doc)
462 cls.def_readwrite(name, &[:Mem:], doc);
463 else
464 cls.def_readwrite(name, &[:Mem:]);
465 }
466 }
467
470 template <auto Fns, class Style = ::welder::naming::none>
471 static void add_method(auto& cls) {
472 constexpr const char* name{
474 template for (constexpr auto fn : std::define_static_array(Fns)) {
475 _def_function<fn>(name, [&cls](auto&&... a) {
476 cls.def(std::forward<decltype(a)>(a)...);
477 });
478 }
479 }
480
482 template <auto Fns, class Style = ::welder::naming::none>
483 static void add_static_method(auto& cls) {
484 constexpr const char* name{
485 ::welder::name_of<Fns[0], language, Style,
487 template for (constexpr auto fn : std::define_static_array(Fns)) {
488 _def_function<fn>(name, [&cls](auto&&... a) {
489 cls.def_static(std::forward<decltype(a)>(a)...);
490 });
491 }
492 }
493
496 template <auto Fns>
497 static void add_operator(auto& cls) {
498 constexpr const char* name{::welder::rods::python::operator_dunder(Fns[0])};
499 template for (constexpr auto fn : std::define_static_array(Fns)) {
500 _def_function<fn>(name, [&cls](auto&&... a) {
501 cls.def(std::forward<decltype(a)>(a)...);
502 });
503 }
504 }
505
506 // --- enum binding -------------------------------------------------------
507
520 template <class E>
521 struct enum_handle {
522 py::object scope;
524 const char* name;
525 std::unique_ptr<py::native_enum<E>> impl;
526
530 void value(const char* n, E v) { impl->value(n, v); }
532 void export_values() { impl->export_values(); }
533
536 void finalize() {
537 impl->finalize(); // commits the enum onto `scope` as `name`
538 // pybind11 3.0.1 does not yet stamp the `__pybind11_native_enum__`
539 // marker that pybind11-stubgen keys on to recognize a stdlib-enum (and
540 // strip its `enum` internals from the generated .pyi); a later pybind11
541 // sets it. Set it ourselves so welded enums produce clean stubs — both
542 // welder's own and any run by a consumer. Harmless once pybind11 sets it
543 // too; drop when the conan pybind11 package carries it.
544 scope.attr(name).attr("__pybind11_native_enum__") = true;
545 }
546 };
547
556 template <class T>
558 std::declval<module_type&>(), nullptr, nullptr, std::index_sequence<>{}));
559 template <class E> using enum_handle_type = enum_handle<E>;
560
563 template <class E>
564 static enum_handle<E> make_enum(module_type& m, const char* name,
565 const char* doc) {
566 // native_enum's class_doc "" means "leave __doc__ untouched"; a non-null doc
567 // is the enum docstring, applied at finalize().
568 return {m, name,
569 std::make_unique<py::native_enum<E>>(m, name, "enum.IntEnum",
570 doc ? doc : "")};
571 }
572
577 template <class E>
579 const char* name, const char* doc) {
580 return {outer_cls, name,
581 std::make_unique<py::native_enum<E>>(outer_cls, name,
582 "enum.IntEnum",
583 doc ? doc : "")};
584 }
585
587 template <std::meta::info Enum, class Style = ::welder::naming::none>
588 static void add_enumerator(auto& e) {
589 e.value(
591 [:Enum:]);
592 }
593
596 template <class E>
597 static void finish_enum(auto& e) {
598 // Mirror C++ scope semantics: an unscoped enum's enumerators are visible
599 // unqualified, so export them into the enclosing scope; a scoped enum's
600 // are reached as E.Value, so leave them scoped.
601 if constexpr (!std::is_scoped_enum_v<E>)
602 e.export_values();
603 e.finalize(); // native_enum requires an explicit finalize()
604 }
605
606 // --- namespace / module binding -----------------------------------------
607
611 static py::dict open_module(module_type&) { return py::dict{}; }
612
614 static void set_module_doc(module_type& m, const char* doc) { m.doc() = doc; }
615
623 template <auto Fns, class Style = ::welder::naming::none>
624 static py::object add_function(module_type& m, const char* name = nullptr) {
625 const char* fn_name{::welder::name_of_or<Fns[0], language, Style,
627 template for (constexpr auto fn : std::define_static_array(Fns)) {
628 _def_function<fn>(fn_name, [&m](auto&&... a) {
629 m.def(std::forward<decltype(a)>(a)...);
630 });
631 }
632 return m.attr(fn_name);
633 }
634
641 template <std::meta::info Var, class Style = ::welder::naming::none>
642 static void add_variable(module_type& m, py::dict& live,
643 const char* name_override = nullptr) {
644 const char* name{
646 name_override)};
647 if constexpr (std::meta::is_const_type(std::meta::type_of(Var))) {
648 m.attr(name) = [:Var:]; // immutable: a value snapshot at bind time
649 } else {
650 // Mutable: a live property over the C++ global. The descriptors take a
651 // leading `self` (the module) and ignore it.
652 auto property{py::module_::import("builtins").attr("property")};
653 live[name] = property(
654 py::cpp_function([](py::object) { return [:Var:]; }),
655 py::cpp_function([](py::object,
656 typename [:std::meta::type_of(Var):] v) {
657 [:Var:] = v;
658 }));
659 }
660 }
661
663 static module_type add_submodule(module_type& m, const char* name) {
664 return m.def_submodule(name);
665 }
666
668 static void close_module(module_type& m, py::dict& live) {
669 if (live.size() != 0)
671 }
672};
673
674static_assert(::welder::rod<rod<>>,
675 "welder::rods::pybind11::rod<> must satisfy welder::rod");
676
677} // namespace welder::rods::pybind11
Backend-agnostic selection layer: the reflection predicates and selectors that decide what participat...
The contract a rod (a welder backend, welder::rods::…::rod) must satisfy to plug into the generic dri...
Definition concepts.hpp:206
Language-agnostic documentation layer: read [[=welder::doc(...)]] annotations off reflected entities ...
Docstring styles shared by welder's Python backends.
consteval auto aggregate_fields()
The fields an aggregate is initialized from: its non-static data members in declaration order (all pu...
consteval auto param_types()
A function's parameter types, as a static array of reflections.
consteval bool all_params_named()
Whether every parameter of Fn carries an identifier.
consteval auto param_names()
A function's parameter names, in order.
consteval auto keep_alive_pairs()
The keep_alive dependencies declared on Fn, in declaration order.
consteval const char * operator_dunder(std::meta::info f)
The Python special-method ("dunder") name for a member operator, or nullptr if welder does not expose...
Definition operators.hpp:39
consteval std::meta::info construction_type_of()
The type welder constructs when binding T: its registered/annotated trampoline if one exists,...
consteval detail::doc_spec< N > doc(const char(&s)[N])
Attach a docstring to a namespace, class, function, or function parameter.
lang
The target languages welder ships rods for — but not the whole value space.
Definition lang.hpp:42
@ py
Python (via the pybind11 and nanobind backends).
Definition lang.hpp:43
rv_kind
How a bound callable's returned object is owned/converted in the target language — welder's backend-n...
@ none
Do not convert (nanobind rv_policy::none); pybind11 has no equivalent.
@ static_method
a static member function → transform_static_method.
Definition naming.hpp:244
@ function
a free function → transform_function.
Definition naming.hpp:245
consteval void validate_return_policy()
Reject a return_policy on Fn (for language L) that contradicts Fn's return type.
Definition reflect.hpp:253
constexpr const char * name_of_or(const char *override_)
Resolve a bound name with a call-site override: override_ wins verbatim, nullptr falls back to name_o...
Definition naming.hpp:343
std::string function_docstring()
The complete docstring for function Fn under Style.
Definition doc.hpp:276
consteval const char * name_of()
The final bound name of Ent (a K-kind entity) for language L under name style Style.
Definition naming.hpp:294
consteval const char * doc_of()
The doc text on Ent (a class, namespace, function, or parameter), or nullptr.
Definition doc.hpp:138
consteval rv_kind return_policy_of(std::meta::info fn, lang L)
The return-value policy declared on callable fn for language L.
Definition reflect.hpp:229
The C++-operator → Python special-method ("dunder") map shared by welder's Python backends.
Splice-based accessors for data member Mem — the pointer-to-member-free route the rods bind a protect...
Owning handle for a py::native_enum<E>, plus the scope + name to reach the finalized enum object.
Definition rod.hpp:521
void value(const char *n, E v)
Add enumerator n = v to the pending native enum.
Definition rod.hpp:530
py::object scope
the enclosing scope: a (sub)module, or — for a nested enum — the enclosing class handle
Definition rod.hpp:522
const char * name
the enum's Python name
Definition rod.hpp:524
void finalize()
Commit the enum onto scope as name, and stamp the pybind11-stubgen native-enum marker.
Definition rod.hpp:536
std::unique_ptr< py::native_enum< E > > impl
the (move-only) native enum
Definition rod.hpp:525
void export_values()
Export the enumerators into the enclosing scope (unscoped enums).
Definition rod.hpp:532
decltype(make_class< T, std::array< std::meta::info, 0 >{}>( std::declval< module_type & >(), nullptr, nullptr, std::index_sequence<>{})) class_handle_type
The class / enum handles the per-class / per-enum hooks operate on — exactly what make_class / make_e...
Definition rod.hpp:557
static auto make_nested_class(module_type &, auto &outer_cls, const char *name, const char *doc, std::index_sequence< I... > seq)
Create the py::class_ for a nested member type T, registered under its enclosing type's class handle ...
Definition rod.hpp:392
static constexpr lang language
welder::lang::py.
Definition rod.hpp:72
static void finish_enum(auto &e)
Finalize enum E: export an unscoped enum's values into the enclosing scope, then commit the enum to t...
Definition rod.hpp:597
static module_type add_submodule(module_type &m, const char *name)
Create a submodule named name under m.
Definition rod.hpp:663
static void add_field(auto &cls)
Bind data member Mem as an attribute.
Definition rod.hpp:426
static void add_operator(auto &cls)
Bind operator overload group Fns under its Python dunder (one operator + arity per group,...
Definition rod.hpp:497
static auto _make_class(py::handle scope, const char *name, const char *doc, std::index_sequence< I... >)
Construct py::class_<T, NativeBases...> from a reflected base-type array.
Definition rod.hpp:282
static void add_method(auto &cls)
Bind method overload group Fns (name from Fns[0]; pybind11 chains one .def per overload and dispatche...
Definition rod.hpp:471
static void _def_function(const char *name, Def def_into)
Convenience overload: derive the parameter and keep_alive index sequences from Fn.
Definition rod.hpp:194
static void _install_live_properties(py::module_ &m, py::dict props)
Give module m live get/set semantics for the names in props.
Definition rod.hpp:252
static constexpr bool has_native_caster
caster_oracle: T is convertible without welder registering a class for it iff pybind11 does not fall ...
Definition rod.hpp:353
static void set_module_doc(module_type &m, const char *doc)
Set the (sub)module docstring.
Definition rod.hpp:614
static void add_constructors(auto &cls)
Bind T's whole constructor set (a chained-def framework just loops it): the default constructor when ...
Definition rod.hpp:402
static consteval py::return_value_policy _return_value_policy(::welder::rv_kind k)
Map welder's neutral welder::rv_kind to pybind11's return_value_policy.
Definition rod.hpp:131
py::module_ module_type
pybind11's module handle.
Definition rod.hpp:73
static void close_module(module_type &m, py::dict &live)
Close the session: apply any accumulated live properties.
Definition rod.hpp:668
static auto _make_class_at(py::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_cla...
Definition rod.hpp:307
static void _def_init(auto &cls, std::index_sequence< I... >)
Register py::init<P0, P1, …>() for constructor Ctor.
Definition rod.hpp:210
[:::welder::rods::python::construction_type_of< T >() :] construction_type
The type welder constructs when binding T — its registered trampoline if one exists,...
Definition rod.hpp:368
static constexpr bool _needs_registration
Whether pybind11 can only convert T via runtime class registration.
Definition rod.hpp:118
static py::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 ....
Definition rod.hpp:624
static enum_handle< E > make_enum(module_type &m, const char *name, const char *doc)
Create the enum_handle for E (a non-null doc becomes its docstring).
Definition rod.hpp:564
enum_handle< E > enum_handle_type
Definition rod.hpp:559
static void add_static_method(auto &cls)
Bind static-method overload group Fns.
Definition rod.hpp:483
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 pybind11 target.
Definition rod.hpp:163
static consteval const char * special_method_name(std::meta::info op_fn)
Map a member operator to its Python dunder (nullptr = not exposed).
Definition rod.hpp:357
static auto make_class(module_type &m, const char *name, const char *doc, std::index_sequence< I... > seq)
Create the py::class_<T, Bases…> handle, weaving in a trampoline when T is a welded virtual type with...
Definition rod.hpp:381
static void add_variable(module_type &m, py::dict &live, const char *name_override=nullptr)
Bind namespace variable Var as a module attribute.
Definition rod.hpp:642
static void _def_aggregate_init(auto &cls, std::index_sequence< I... >)
Synthesize a field constructor for a baseless aggregate T.
Definition rod.hpp:229
static py::dict open_module(module_type &)
Open a per-module session: a dict accumulating live (mutable-variable) properties; _install_live_prop...
Definition rod.hpp:611
static enum_handle< E > make_nested_enum(module_type &, auto &outer_cls, const char *name, const char *doc)
Create the enum_handle for a nested member enum E, scoped to its enclosing type's class handle — Pyth...
Definition rod.hpp:578
static void add_enumerator(auto &e)
Add enumerator Enum to the enum handle.
Definition rod.hpp:588
Virtual-function overriding support shared by welder's Python backends.
welder's binding entry point: the welder::welder struct.