44#include <pybind11/pybind11.h>
45#include <pybind11/native_enum.h>
46#include <pybind11/stl_bind.h>
58#define WELDER_OPAQUE(...) PYBIND11_MAKE_OPAQUE(__VA_ARGS__)
86template <::welder::doc_style DocStyle = ::welder::rods::python::google_style>
135 std::is_enum_v<std::remove_cvref_t<T>> ||
136 std::is_base_of_v<py::detail::type_caster_base<py::detail::intrinsic_t<T>>,
137 py::detail::make_caster<T>>;
149 case ::welder::rv_kind::automatic:
return py::return_value_policy::automatic;
150 case ::welder::rv_kind::automatic_reference:
return py::return_value_policy::automatic_reference;
151 case ::welder::rv_kind::take_ownership:
return py::return_value_policy::take_ownership;
152 case ::welder::rv_kind::copy:
return py::return_value_policy::copy;
153 case ::welder::rv_kind::move:
return py::return_value_policy::move;
154 case ::welder::rv_kind::reference:
return py::return_value_policy::reference;
155 case ::welder::rv_kind::reference_internal:
return py::return_value_policy::reference_internal;
156 case ::welder::rv_kind::none:
break;
158 return py::return_value_policy::automatic;
178 template <std::meta::info Fn,
class Def, std::size_t... I, std::size_t... K>
180 std::index_sequence<I...>, std::index_sequence<K...>) {
186 "welder: return_policy 'none' has no pybind11 equivalent "
187 "(it is nanobind-only) — choose another policy");
192 def_into(name, &[:Fn:], py::arg(names[I])..., rvp,
193 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
195 def_into(name, &[:Fn:],
doc.c_str(), py::arg(names[I])..., rvp,
196 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
199 def_into(name, &[:Fn:], rvp,
200 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
202 def_into(name, &[:Fn:],
doc.c_str(), rvp,
203 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
216 template <std::meta::info Fn,
class Self,
class Def, std::size_t... I>
218 std::index_sequence<I...>) {
221 [[maybe_unused]]
static constexpr auto params{
224 constexpr py::return_value_policy rvp{
226 if constexpr (std::is_void_v<Self>) {
227 auto wrapper = [](
typename [:params[I]:]... a) ->
decltype(
auto) {
228 return [:Fn:](std::forward<typename [:params[I]:]>(a)...);
231 def_into(name, wrapper, py::arg(names[I])..., rvp);
233 def_into(name, wrapper, rvp);
235 auto wrapper = [](Self& self,
236 typename [:params[I]:]... a) ->
decltype(
auto) {
237 return self.[:Fn:](std::forward<typename [:params[I]:]>(a)...);
240 def_into(name, wrapper, py::arg(names[I])..., rvp);
242 def_into(name, wrapper, rvp);
248 template <std::meta::info Fn,
class Self,
class Def, std::size_t... K>
250 std::index_sequence<K...>) {
251 constexpr std::size_t P{std::meta::parameters_of(Fn).size()};
252 constexpr std::size_t D{
sizeof...(K)};
254 std::make_index_sequence<P - D + K>{}),
260 template <std::meta::info Fn,
class Def>
264 std::make_index_sequence<std::meta::parameters_of(Fn).size()>{},
265 std::make_index_sequence<
284 template <std::meta::info Ctor, std::size_t D, std::size_t... K>
286 constexpr std::size_t P{std::meta::parameters_of(Ctor).size()};
290 template <std::meta::info Ctor, std::size_t... I>
291 static void _def_init(
auto& cls, std::index_sequence<I...>) {
295 cls.def(py::init<
typename [:params[I]:]...>(), py::arg(names[I])...);
297 cls.def(py::init<
typename [:params[I]:]...>());
323 py::object cls{py::type::of(self)};
324 py::object out{cls.attr(
"__new__")(cls)};
326 (*memo)[py::int_(
reinterpret_cast<std::uintptr_t
>(self.ptr()))] =
335 namespace pd = py::detail;
336 const pd::type_info* tinfo{pd::get_type_info(
typeid(T))};
337 auto* inst{
reinterpret_cast<pd::instance*
>(out.ptr())};
338 pd::value_and_holder v_h{inst->get_value_and_holder(tinfo)};
339 const T& src{py::cast<const T&>(self)};
340 v_h.value_ptr() = Py_TYPE(out.ptr()) != tinfo->type
343 tinfo->init_instance(inst,
nullptr);
344 if (py::hasattr(self,
"__dict__")) {
345 py::object d{self.attr(
"__dict__")};
347 d = py::module_::import(
"copy").attr(
"deepcopy")(d, *memo);
348 out.attr(
"__dict__").attr(
"update")(d);
350 for (py::handle name :
351 py::module_::import(
"copyreg").attr(
"_slotnames")(cls)) {
352 if (!py::hasattr(self, name))
354 py::object v{py::getattr(self, name)};
356 v = py::module_::import(
"copy").attr(
"deepcopy")(v, *memo);
357 py::setattr(out, name, v);
367 template <
class T, std::
size_t I>
370 using field_type = std::remove_const_t<
380 template <
class T, std::
size_t I>
383 std::optional<std::remove_const_t<
386 typename [:std::meta::type_of(::
welder::
detail::aggregate_fields<T>()[I]):]>>;
394 template <
class T, std::
size_t I>
397 constexpr auto field =
403 return std::move(arg);
418 template <
class T, std::
size_t I>
421 constexpr const char* name{
422 std::define_static_string(std::meta::identifier_of(fields[I]))};
427 return py::arg_v(name, py::none(),
"...");
429 return py::arg(name) = probe.[:fields[I]:];
431 return py::arg(name);
447 template <
class T, std::size_t... I>
462 [](
typename [:std::meta::type_of(fields[I]):]... args) {
463 return T{std::move(args)...};
465 py::arg(std::define_static_string(
466 std::meta::identifier_of(fields[I])))...);
485 auto builtins{py::module_::import(
"builtins")};
486 auto subclass{builtins.attr(
"type")(
487 py::str(
"welder_live_module"),
488 py::make_tuple(m.attr(
"__class__")), props)};
496 subclass.attr(
"__module__") = m.attr(
"__name__");
497 m.attr(
"__class__") = subclass;
513 template <
class T,
class Trampoline,
auto Bases, std::size_t... I>
515 std::index_sequence<I...>) {
516 if constexpr (std::is_void_v<Trampoline>) {
518 return py::class_<T,
typename [:Bases[I]:]...>(scope, name,
doc);
519 return py::class_<T,
typename [:Bases[I]:]...>(scope, name);
524 return py::class_<T, Trampoline,
typename [:Bases[I]:]...>(scope, name,
doc);
525 return py::class_<T, Trampoline,
typename [:Bases[I]:]...>(scope, name);
538 template <
class T,
auto Bases, std::size_t... I>
540 const char*
doc, std::index_sequence<I...> seq) {
545 constexpr auto scanned{py_::scanned_trampoline_of(^^T)};
547 py_::trampoline_for<T> != std::meta::info{} || !scanned.ambiguous,
548 "welder: more than one [[=welder::rods::python::trampoline]] class in "
549 "this namespace derives from T; disambiguate by specializing "
550 "welder::rods::python::trampoline_for<T>.");
551 constexpr std::meta::info tramp{py_::trampoline_for<T> != std::meta::info{}
552 ? py_::trampoline_for<T>
554 if constexpr (tramp != std::meta::info{}) {
555 using Trampoline = [:tramp:];
557 py_::trampoline_covers(^^T, ^^Trampoline),
558 "welder: the trampoline registered for this type does not "
559 "override all of its virtual methods; every virtual needs an "
560 "override forwarding to Python (see WELDER_PY_OVERRIDE).");
565 "welder: this welded type has virtual methods but no trampoline "
566 "is registered, so a Python subclass could not override them. "
567 "Register one — a [[=welder::rods::python::trampoline]] subclass "
568 "in T's namespace, or a welder::rods::python::trampoline_for<T> "
569 "specialization — or annotate T with "
570 "[[=welder::bind_flat]] to bind it non-overridably.");
590 return ::welder::rods::python::operator_dunder(op_fn);
612 template <
class T,
auto Bases, std::size_t... I>
614 std::index_sequence<I...> seq) {
623 template <
class T,
auto Bases, std::size_t... I>
625 const char*
doc, std::index_sequence<I...> seq) {
647 template <
class T,
auto Ctors,
bool HasDefault,
bool Aggregate,
bool Copyable,
650 if constexpr (HasDefault)
651 cls.def(py::init<>());
652 if constexpr (Copyable) {
657 std::is_constructible_v<construction_type<T>,
const T&>,
658 "welder: this type's trampoline lacks a copy-from-base "
659 "constructor, so a copied Python-subclass instance would hold a "
660 "plain base payload and silently stop dispatching virtuals into "
661 "Python. The WELDER_PY_TRAMPOLINE(TRAMP, BASE) macro declares "
662 "it; a hand-rolled trampoline needs 'Tramp(const Base&)' — or "
663 "mark::exclude the copy constructor.");
668 cls.def(
"__copy__", [](py::handle self) {
673 [](py::handle self, py::object memo) {
678 template for (
constexpr auto ctor : std::define_static_array(Ctors)) {
680 std::meta::parameters_of(ctor).size()>{});
684 std::make_index_sequence<d>{});
686 if constexpr (Aggregate) {
703 template <std::meta::info Mem,
class Style = ::welder::naming::none>
705 constexpr const char* name{
712 constexpr bool read_only{std::meta::is_const_type(std::meta::type_of(Mem)) ||
714 if constexpr (!std::meta::is_public(Mem)) {
720 if constexpr (read_only) {
722 cls.def_property_readonly(
723 name, &fa::get, py::return_value_policy::reference_internal,
726 cls.def_property_readonly(
728 py::return_value_policy::reference_internal);
731 cls.def_property(name, &fa::get, &fa::set,
732 py::return_value_policy::reference_internal,
735 cls.def_property(name, &fa::get, &fa::set,
736 py::return_value_policy::reference_internal);
738 }
else if constexpr (read_only) {
740 cls.def_readonly(name, &[:Mem:],
doc);
742 cls.def_readonly(name, &[:Mem:]);
745 cls.def_readwrite(name, &[:Mem:],
doc);
747 cls.def_readwrite(name, &[:Mem:]);
762 template <
class T, std::meta::info Getter, std::meta::info Setter>
767 "welder: return_policy 'none' has no pybind11 equivalent "
768 "(it is nanobind-only) — choose another policy");
770 auto def{[&](
auto&&... extra) {
771 if constexpr (Setter == std::meta::info{}) {
772 cls.def_property_readonly(name, &[:Getter:],
773 std::forward<
decltype(extra)>(extra)...);
774 }
else if constexpr (std::is_void_v<
775 typename [:std::meta::return_type_of(Setter):]>) {
776 cls.def_property(name, &[:Getter:], &[:Setter:],
777 std::forward<
decltype(extra)>(extra)...);
784 [:std::meta::type_of(std::meta::parameters_of(Setter)[0]):];
785 static constexpr auto sp{&[:Setter:]};
788 [](T& self, Arg v) { (self.*sp)(std::forward<Arg>(v)); },
789 std::forward<decltype(extra)>(extra)...);
808 template <auto Fns,
class Style = ::welder::naming::none>
810 constexpr const char* name{
812 template for (
constexpr auto fn : std::define_static_array(Fns)) {
814 cls.def(std::forward<
decltype(a)>(a)...);
819 fn,
typename std::remove_reference_t<
decltype(cls)>::type>(
821 [&cls](
auto&&... a) {
822 cls.def(std::forward<
decltype(a)>(a)...);
824 std::make_index_sequence<d>{});
829 template <auto Fns,
class Style = ::welder::naming::none>
831 constexpr const char* name{
834 template for (
constexpr auto fn : std::define_static_array(Fns)) {
836 cls.def_static(std::forward<
decltype(a)>(a)...);
842 [&cls](
auto&&... a) {
843 cls.def_static(std::forward<
decltype(a)>(a)...);
845 std::make_index_sequence<d>{});
859 template <
class T, auto Fns>
861 template for (
constexpr auto fn : std::define_static_array(Fns)) {
868 std::make_index_sequence<
884 template <
class T, auto Fns, auto Covered>
887 [&cls](
const char* name,
auto fp) {
888 cls.def(name, fp, py::is_operator{});
894 template <
class T, std::meta::info Fn>
907 template <std::meta::info Fn,
bool NotImpl,
class Cls, std::size_t... K>
909 std::index_sequence<K...>) {
914 "welder: return_policy 'none' has no pybind11 equivalent "
915 "(it is nanobind-only) — choose another policy");
918 auto def{[&](
auto&&... extra) {
920 cls.def(name, &[:Fn:], rvp,
921 py::keep_alive<ka[K].nurse, ka[K].patient>()...,
922 std::forward<
decltype(extra)>(extra)...);
924 cls.def(name, &[:Fn:],
doc.c_str(), rvp,
925 py::keep_alive<ka[K].nurse, ka[K].patient>()...,
926 std::forward<
decltype(extra)>(extra)...);
928 if constexpr (NotImpl)
929 def(py::is_operator{});
937 template <
class T, std::meta::info Fn>
940 if constexpr (name !=
nullptr) {
943 [:std::meta::type_of(std::meta::parameters_of(Fn)[0]):];
946 [](
const T& self, Lhs lhs) {
947 return [:Fn:](
static_cast<Lhs&&
>(lhs), self);
974 std::unique_ptr<py::native_enum<E>>
impl;
993 scope.attr(
name).attr(
"__pybind11_native_enum__") =
true;
1007 std::declval<module_type&>(),
nullptr,
nullptr, std::index_sequence<>{}));
1022 return py::reinterpret_borrow<class_handle_type<T>>(scope.attr(name));
1030 return py::reinterpret_borrow<class_handle_type<T>>(outer.attr(name));
1040 return DocStyle::format_enum(ed);
1047 const ::welder::detail::enum_doc& ed) {
1053 std::make_unique<py::native_enum<E>>(m, name,
"enum.IntEnum",
1065 const ::welder::detail::enum_doc& ed) {
1067 return {outer_cls, name,
1068 std::make_unique<py::native_enum<E>>(outer_cls, name,
1074 template <std::meta::info Enum,
class Style = ::welder::naming::none>
1088 if constexpr (!std::is_scoped_enum_v<E>)
1110 template <auto Fns,
class Style = ::welder::naming::none>
1114 template for (
constexpr auto fn : std::define_static_array(Fns)) {
1116 m.def(std::forward<
decltype(a)>(a)...);
1119 if constexpr (d > 0)
1122 [&m](
auto&&... a) { m.def(std::forward<
decltype(a)>(a)...); },
1123 std::make_index_sequence<d>{});
1125 return m.attr(fn_name);
1134 template <std::meta::info Var,
class Style = ::welder::naming::none>
1136 const char* name_override =
nullptr) {
1140 if constexpr (std::meta::is_const_type(std::meta::type_of(Var))) {
1141 m.attr(name) = [:Var:];
1145 auto property{py::module_::import(
"builtins").attr(
"property")};
1146 live[name] = property(
1147 py::cpp_function([](py::object) {
return [:Var:]; }),
1148 py::cpp_function([](py::object,
1149 typename [:std::meta::type_of(Var):] v) {
1157 return m.def_submodule(name);
1180 template <
class Container,
class Style = ::welder::naming::none>
1182 constexpr ::welder::container_kind kind{
1185 using Elem =
typename Container::value_type;
1187 std::is_arithmetic_v<Elem> && !std::is_same_v<Elem, bool>) {
1190 auto cls{py::bind_vector<Container>(m, name, py::buffer_protocol())};
1197 auto cls{py::bind_vector<Container>(m, name)};
1202 auto cls{py::bind_vector<Container>(m, name)};
1211 py::bind_map<Container>(m, name);
1232 template <
class Container>
1234 using Elem =
typename Container::value_type;
1235 constexpr std::size_t N{std::tuple_size_v<Container>};
1236 constexpr bool scalar{std::is_arithmetic_v<Elem> &&
1237 !std::is_same_v<Elem, bool>};
1239 if constexpr (scalar)
1240 return py::class_<Container>(m, name, py::buffer_protocol());
1242 return py::class_<Container>(m, name);
1244 cls.def(py::init<>());
1245 cls.def(py::init<const Container&>());
1248 cls.def(py::init([](
const py::sequence& seq) {
1249 if (py::len(seq) != N)
1250 throw py::value_error(
1251 "expected a sequence of the array's fixed length");
1254 for (py::handle h : seq)
1255 a[i++] = h.cast<Elem>();
1258 py::implicitly_convertible<py::sequence, Container>();
1259 cls.def(
"__len__", [](
const Container&) {
return N; });
1262 [](Container& a, py::ssize_t i) -> Elem& {
1265 py::return_value_policy::reference_internal);
1266 cls.def(
"__setitem__", [](Container& a, py::ssize_t i,
const Elem& v) {
1271 [](Container& a) {
return py::make_iterator(a.begin(), a.end()); },
1272 py::keep_alive<0, 1>());
1273 if constexpr (scalar) {
1275 cls.def_buffer([](Container& a) -> py::buffer_info {
1276 return py::buffer_info(a.data(),
1277 static_cast<py::ssize_t
>(
sizeof(Elem)),
1278 py::format_descriptor<Elem>::format(), 1,
1279 {a.size()}, {sizeof(Elem)});
1292 i +=
static_cast<py::ssize_t
>(n);
1293 if (i < 0 ||
static_cast<std::size_t
>(i) >= n)
1294 throw py::index_error(
"array index out of range");
1295 return static_cast<std::size_t
>(i);
1307 template <
class Container,
class Elem,
class Cls>
1309 using Size =
typename Container::size_type;
1310 if constexpr (
requires(Container& c, Size n) { c.reserve(n); })
1312 "reserve", [](Container& v, Size n) { v.reserve(n); }, py::arg(
"n"),
1313 "Pre-allocate capacity for at least n elements (no-op if capacity "
1314 "already exceeds n). Prevents reallocation — and reference "
1315 "invalidation — across a following run of append()/new().");
1316 if constexpr (
requires(Container& c, Size n) { c.resize(n); })
1318 "resize", [](Container& v, Size n) { v.resize(n); }, py::arg(
"n"),
1319 "Resize to exactly n elements, value-initializing any new tail "
1320 "elements. Shrinking or reallocating invalidates references.");
1331 template <
class Container,
class Elem,
class Cls>
1333 if constexpr (std::is_class_v<Elem> &&
1334 std::is_default_constructible_v<Elem>)
1336 "new", [](Container& v) -> Elem& { return v.emplace_back(); },
1337 py::return_value_policy::reference_internal,
1338 "Default-construct a new element in place at the end and return a "
1339 "live reference to it.");
1347 template <
class Container,
class Elem,
class Cls>
1350 cls.def_property_readonly(
"__array_interface__", [](Container& v) {
1351 static constexpr auto d{pyai::ai_descr<^^Elem>()};
1353 for (
auto [nm, ts] : d)
1354 descr.append(py::make_tuple(nm, ts));
1356 out[
"shape"] = py::make_tuple(v.size());
1357 out[
"typestr"] = pyai::ai_typestr<Elem>();
1358 out[
"descr"] = descr;
1359 out[
"data"] = py::make_tuple(
1360 reinterpret_cast<std::uintptr_t
>(v.data()),
false);
1370 if (live.size() != 0)
1375static_assert(::welder::rod<rod<>>,
1376 "welder::rods::pybind11::rod<> must satisfy welder::rod");
The NumPy array-interface descriptor for an opaque std::vector<T> whose element T is a plain-old-data...
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...
The reference-semantic container table: which STL containers welder can bind opaquely* (by reference)...
Language-agnostic documentation layer: read [[=welder::doc(...)]] annotations off reflected entities ...
Docstring styles shared by welder's Python backends.
The stored forms of the annotation vocabulary.
consteval auto aggregate_fields()
The fields an aggregate is initialized from: its non-static data members in declaration order (all pu...
consteval std::size_t trailing_default_count()
How many TRAILING parameters of Fn carry a C++ default argument.
consteval auto param_types()
A function's parameter types, as a static array of reflections.
consteval bool free_operator_reflected(std::meta::info f, std::meta::info type)
Whether anchored free operator f binds reflected for type: type is the right operand and the left is ...
consteval std::size_t aggregate_defaults_from()
The field index from which a value-extracting backend (the Python rods) can attach the NSDMI defaults...
consteval bool all_params_named()
Whether every parameter of Fn carries an identifier.
std::string stringify(const T &self)
The stringifier wrapper every runtime rod binds for a swept ostream inserter (see is_stringifier_for)...
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 an operator (member or anchored free),...
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 —...
consteval bool dunder_uses_not_implemented(std::meta::info f)
Whether f's slot participates in Python's NotImplemented protocol — every binary arithmetic / bitwise...
consteval bool pod_array_eligible()
Is std::vector<E> viewable as a NumPy structured array — i.e.
void synthesize_comparisons(Def def)
The comparison-synthesis walk shared by both Python backends: for each operator<=> overload in Fns,...
consteval std::meta::info construction_type_of()
The type welder constructs when binding T: its registered/annotated trampoline if one exists,...
consteval bool has_virtual_methods(std::meta::info type)
Does type declare or inherit any overridable virtual method?
consteval bool member_no_reassign(std::meta::info member, lang L)
Is data member member bound read-only for L by a no_reassign mark?
consteval detail::doc_spec< N > doc(const char(&s)[N])
Attach a docstring to a namespace, class, function, or function parameter.
consteval bool container_is_contiguous(std::meta::info type)
Is type a contiguous sequence — one whose elements live in a single block reachable via ....
consteval container_kind container_kind_of(std::meta::info type)
The opaque-binder kind of type.
lang
The target languages welder ships rods for — but not the whole value space.
@ py
Python (via the pybind11 and nanobind backends).
rv_kind
How a bound callable's returned object is owned/converted in the target language — welder's backend-n...
@ automatic
The rod default — emit no explicit policy.
@ none
Do not convert (nanobind rv_policy::none); pybind11 has no equivalent.
@ field
a data member → transform_field.
@ static_method
a static member function → transform_static_method.
@ function
a free function → transform_function.
@ fixed_sequence
A fixed-size sequence: std::array<T, N>.
@ sequence
A bind_vector container: std::vector.
consteval void validate_return_policy()
Reject a return_policy on Fn (for language L) that contradicts Fn's return type.
consteval bool bound_flat(std::meta::info entity)
Does entity (a type or a member function) carry a bind_flat mark?
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...
std::string function_docstring()
The complete docstring for function Fn under Style.
consteval const char * name_of()
The final bound name of Ent (a K-kind entity) for language L under name style Style.
consteval const char * doc_of()
The doc text on Ent (a class, namespace, function, or parameter), or nullptr.
consteval rv_kind return_policy_of(std::meta::info fn, lang L)
The return-value policy declared on callable fn for language L.
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...
The identity style: bind every C++ identifier unchanged.
Owning handle for a py::native_enum<E>, plus the scope + name to reach the finalized enum object.
void value(const char *n, E v)
Add enumerator n = v to the pending native enum.
py::object scope
the enclosing scope: a (sub)module, or — for a nested enum — the enclosing class handle
const char * name
the enum's Python name
void finalize()
Commit the enum onto scope as name, and stamp the pybind11-stubgen native-enum marker.
std::unique_ptr< py::native_enum< E > > impl
the (move-only) native enum
void export_values()
Export the enumerators into the enclosing scope (unscoped enums).
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-thr...
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...
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 ...
static constexpr lang language
welder::lang::py.
static void _def_sizing(Cls &cls)
Give the opaque sequence class cls the reserve(n) / resize(n) sizing methods (which bind_vector does ...
static auto _aggregate_arg(const T &probe)
The py::arg for field I of aggregate T: named after the field and, for the defaultable NSDMI suffix (...
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...
static void add_operator(auto &cls)
Bind operator slot group Fns — one (operator, arity) slot whole, member and anchored free entries mix...
static module_type add_submodule(module_type &m, const char *name)
Create a submodule named name under m.
static void add_field(auto &cls)
Bind data member Mem as an attribute.
static void add_comparisons(auto &cls)
Synthesize the relational dunders from operator<=> group Fns: for each spaceship overload's operand t...
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.
static void add_method(auto &cls)
Bind method overload group Fns (name from Fns[0]; pybind11 chains one .def per overload and dispatche...
static void _def_default_truncations(const char *name, Def def_into, std::index_sequence< K... >)
Bind every omissible arity of Fn — arities P-D .
static void _def_function(const char *name, Def def_into)
Convenience overload: derive the parameter and keep_alive index sequences from Fn.
static void _def_new(Cls &cls)
Give the opaque std::vector<Elem> class cls a new() method that default-constructs an element in plac...
static void _install_live_properties(py::module_ &m, py::dict props)
Give module m live get/set semantics for the names in props.
static constexpr bool has_native_caster
caster_oracle: T is convertible without welder registering a class for it iff pybind11 does not fall ...
static void _array_interface(Cls &cls)
Give the opaque std::vector<Elem> class cls a __array_interface__ property — the numpy array-interfac...
static void set_module_doc(module_type &m, const char *doc)
Set the (sub)module docstring.
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....
static void _def_reflected_operator(auto &cls)
Bind reflected free operator Fn (T is its right operand) under its reflected dunder,...
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.
static void add_constructors(auto &cls)
Bind T's whole constructor set (a chained-def framework just loops it): the default constructor when ...
static std::string _enum_docstring(const ::welder::detail::enum_doc &ed)
Assemble ed — the enum summary plus its documented enumerators — into the enum's class docstring unde...
py::module_ module_type
pybind11's module handle.
static enum_handle< E > make_nested_enum(module_type &, auto &outer_cls, const char *name, const ::welder::detail::enum_doc &ed)
Create the enum_handle for a nested member enum E, scoped to its enclosing type's class handle — Pyth...
static void close_module(module_type &m, py::dict &live)
Close the session: apply any accumulated live properties.
static py::object _copy_instance(py::handle self, py::object *memo)
The subclass-faithful engine behind __copy__/__deepcopy__.
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 (welder::ca...
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...
std::conditional_t< _lazy_default< T, I >(), std::optional< std::remove_const_t< typename[:std::meta::type_of(::welder::detail::aggregate_fields< T >()[I]):]> >, std::remove_const_t< typename[:std::meta::type_of(::welder::detail::aggregate_fields< T >()[I]):]> > _init_param
The synthesized constructor's parameter type for field I of T: std::optional<F> for a lazy default,...
static void _def_init(auto &cls, std::index_sequence< 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 pybind11 mirror of t...
[:::welder::rods::python::construction_type_of< T >() :] construction_type
The type welder constructs when binding T — its registered trampoline if one exists,...
static constexpr bool _needs_registration
Whether pybind11 can only convert T via runtime class registration.
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 ....
enum_handle< E > enum_handle_type
static void add_static_method(auto &cls)
Bind static-method overload group Fns.
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.
static void add_stringifier(auto &cls)
Bind the swept free ostream inserter Fn as __str__ (via welder::detail::stringify).
static consteval const char * special_method_name(std::meta::info op_fn)
Map a member operator to its Python dunder (nullptr = not exposed).
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...
static void add_variable(module_type &m, py::dict &live, const char *name_override=nullptr)
Bind namespace variable Var as a module attribute.
static consteval bool _lazy_default()
Whether field I of aggregate T binds its NSDMI default LAZILY — the same rule (and reason) as the nan...
static void _def_aggregate_init(auto &cls, std::index_sequence< I... >)
Synthesize a field constructor for a baseless aggregate T.
static py::dict open_module(module_type &)
Open a per-module session: a dict accumulating live (mutable-variable) properties; _install_live_prop...
static void add_property(auto &cls, const char *name)
Bind the resolved property (Getter + optional Setter) as a Python property named name (driver-resolve...
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.
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...
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,...
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 pl...
static enum_handle< E > make_enum(module_type &m, const char *name, const ::welder::detail::enum_doc &ed)
Create the enum_handle for E; ed's summary + enumerator docs become its class docstring (see _enum_do...
static void _def_init_truncations(auto &cls, std::index_sequence< K... >)
Register py::init<P0, P1, …>() for constructor Ctor.
static void add_enumerator(auto &e)
Add enumerator Enum to the enum handle.
Virtual-function overriding support shared by welder's Python backends.
welder's binding entry point: the welder::welder struct.