50#include <nanobind/nanobind.h>
51#include <nanobind/ndarray.h>
52#include <nanobind/stl/bind_vector.h>
53#include <nanobind/stl/optional.h>
54#include <nanobind/stl/bind_map.h>
68#define WELDER_OPAQUE(...) NB_MAKE_OPAQUE(__VA_ARGS__)
96template <::welder::doc_style DocStyle = ::welder::rods::python::google_style>
138 std::is_enum_v<std::remove_cvref_t<T>> ||
139 nb::detail::is_base_caster_v<nb::detail::make_caster<T>>;
148 case ::welder::rv_kind::automatic:
return nb::rv_policy::automatic;
149 case ::welder::rv_kind::automatic_reference:
return nb::rv_policy::automatic_reference;
150 case ::welder::rv_kind::take_ownership:
return nb::rv_policy::take_ownership;
151 case ::welder::rv_kind::copy:
return nb::rv_policy::copy;
152 case ::welder::rv_kind::move:
return nb::rv_policy::move;
153 case ::welder::rv_kind::reference:
return nb::rv_policy::reference;
154 case ::welder::rv_kind::reference_internal:
return nb::rv_policy::reference_internal;
155 case ::welder::rv_kind::none:
return nb::rv_policy::none;
157 return nb::rv_policy::automatic;
184 template <std::meta::info Fn,
class Style>
186 constexpr std::size_t n{std::meta::parameters_of(Fn).size()};
187 std::array<const char*, n> names{};
189 for (
auto p : std::meta::parameters_of(Fn))
190 names[i++] = std::meta::has_identifier(p)
191 ? std::define_static_string(Style::transform_field(p))
196 template <std::meta::info Fn,
class Style,
class Def, std::size_t... I, std::size_t... K>
198 std::index_sequence<I...>, std::index_sequence<K...>) {
206 def_into(name, &[:Fn:], nb::arg(names[I])..., rvp,
207 nb::keep_alive<ka[K].nurse, ka[K].patient>()...);
209 def_into(name, &[:Fn:],
doc.c_str(), nb::arg(names[I])..., rvp,
210 nb::keep_alive<ka[K].nurse, ka[K].patient>()...);
213 def_into(name, &[:Fn:], rvp,
214 nb::keep_alive<ka[K].nurse, ka[K].patient>()...);
216 def_into(name, &[:Fn:],
doc.c_str(), rvp,
217 nb::keep_alive<ka[K].nurse, ka[K].patient>()...);
235 template <std::meta::info Fn,
class Self,
class Style,
class Def, std::size_t... I>
237 std::index_sequence<I...>) {
240 [[maybe_unused]]
static constexpr auto params{
243 constexpr nb::rv_policy rvp{
245 if constexpr (std::is_void_v<Self>) {
246 auto wrapper = [](
typename [:params[I]:]... a) ->
decltype(
auto) {
247 return [:Fn:](std::forward<typename [:params[I]:]>(a)...);
250 def_into(name, wrapper, nb::arg(names[I])..., rvp);
252 def_into(name, wrapper, rvp);
254 auto wrapper = [](Self& self,
255 typename [:params[I]:]... a) ->
decltype(
auto) {
256 return self.[:Fn:](std::forward<typename [:params[I]:]>(a)...);
259 def_into(name, wrapper, nb::arg(names[I])..., rvp);
261 def_into(name, wrapper, rvp);
268 template <std::meta::info Fn,
class Self,
class Style,
class Def, std::size_t... K>
270 std::index_sequence<K...>) {
271 constexpr std::size_t P{std::meta::parameters_of(Fn).size()};
272 constexpr std::size_t D{
sizeof...(K)};
274 std::make_index_sequence<P - D + K>{}),
280 template <std::meta::info Fn,
class Style,
class Def>
284 std::make_index_sequence<std::meta::parameters_of(Fn).size()>{},
285 std::make_index_sequence<
304 template <std::meta::info Ctor, std::size_t D,
class Style, std::size_t... K>
306 constexpr std::size_t P{std::meta::parameters_of(Ctor).size()};
310 template <std::meta::info Ctor,
class Style, std::size_t... I>
311 static void _def_init(
auto& cls, std::index_sequence<I...>) {
315 cls.def(nb::init<
typename [:params[I]:]...>(), nb::arg(names[I])...);
317 cls.def(nb::init<
typename [:params[I]:]...>());
345 nb::borrow(
reinterpret_cast<PyObject*
>(Py_TYPE(self.ptr())))};
346 nb::object out{cls.attr(
"__new__")(cls)};
348 (*memo)[nb::int_(
reinterpret_cast<std::uintptr_t
>(self.ptr()))] =
357 const T& src{nb::cast<const T&>(self)};
358 if (nb::detail::nb_inst_python_derived(out.ptr()))
361 new (nb::inst_ptr<void>(out)) T(src);
362 nb::inst_mark_ready(out);
363 if (nb::hasattr(self,
"__dict__")) {
364 nb::object d{self.attr(
"__dict__")};
366 d = nb::module_::import_(
"copy").attr(
"deepcopy")(d, *memo);
367 out.attr(
"__dict__").attr(
"update")(d);
369 for (nb::handle name :
370 nb::module_::import_(
"copyreg").attr(
"_slotnames")(cls)) {
371 if (!nb::hasattr(self, name))
373 nb::object v{nb::getattr(self, name)};
375 v = nb::module_::import_(
"copy").attr(
"deepcopy")(v, *memo);
376 nb::setattr(out, name, v);
392 template <
class T, std::
size_t I>
395 using field_type = std::remove_const_t<
406 template <
class T, std::
size_t I>
409 std::optional<std::remove_const_t<
412 typename [:std::meta::type_of(::
welder::
detail::aggregate_fields<T>()[I]):]>>;
420 template <
class T, std::
size_t I>
423 constexpr auto field =
429 return std::move(arg);
445 template <
class T, std::
size_t I,
class Style>
454 return (nb::arg(name).sig(
"...") = nb::none());
456 return nb::arg(name) = probe.[:fields[I]:];
458 return nb::arg(name);
475 template <
class T,
class Style, std::size_t... I>
493 [](T* self,
typename [:std::meta::type_of(fields[I]):]... args) {
494 new (self) T{std::move(args)...};
516 auto builtins{nb::module_::import_(
"builtins")};
517 auto subclass{builtins.attr(
"type")(
518 nb::str(
"welder_live_module"),
519 nb::make_tuple(m.attr(
"__class__")), props)};
524 subclass.attr(
"__module__") = m.attr(
"__name__");
525 m.attr(
"__class__") = subclass;
543 template <
class T,
class Trampoline,
auto Bases, std::size_t... I>
545 std::index_sequence<I...>) {
546 if constexpr (std::is_void_v<Trampoline>) {
548 return nb::class_<T,
typename [:Bases[I]:]...>(scope, name,
doc);
549 return nb::class_<T,
typename [:Bases[I]:]...>(scope, name);
555 return nb::class_<T, Trampoline,
typename [:Bases[I]:]...>(scope, name,
doc);
556 return nb::class_<T, Trampoline,
typename [:Bases[I]:]...>(scope, name);
564 template <
class T,
auto Bases, std::size_t... I>
566 const char*
doc, std::index_sequence<I...> seq) {
571 constexpr auto scanned{py::scanned_trampoline_of(^^T)};
573 py::trampoline_for<T> != std::meta::info{} || !scanned.ambiguous,
574 "welder: more than one [[=welder::rods::python::trampoline]] class in "
575 "this namespace derives from T; disambiguate by specializing "
576 "welder::rods::python::trampoline_for<T>.");
577 constexpr std::meta::info tramp{py::trampoline_for<T> != std::meta::info{}
578 ? py::trampoline_for<T>
580 if constexpr (tramp != std::meta::info{}) {
581 using Trampoline = [:tramp:];
583 py::trampoline_covers(^^T, ^^Trampoline),
584 "welder: the trampoline registered for this type does not "
585 "override all of its virtual methods; every virtual needs an "
586 "override forwarding to Python (see WELDER_PY_OVERRIDE).");
591 "welder: this welded type has virtual methods but no trampoline "
592 "is registered, so a Python subclass could not override them. "
593 "Register one — a [[=welder::rods::python::trampoline]] subclass "
594 "in T's namespace, or a welder::rods::python::trampoline_for<T> "
595 "specialization — or annotate T with "
596 "[[=welder::bind_flat]] to bind it non-overridably.");
616 return ::welder::rods::python::operator_dunder(op_fn);
638 template <
class T,
auto Bases, std::size_t... I>
640 std::index_sequence<I...> seq) {
649 template <
class T,
auto Bases, std::size_t... I>
651 const char*
doc, std::index_sequence<I...> seq) {
663 std::declval<module_type&>(),
nullptr,
nullptr, std::index_sequence<>{}));
676 return nb::borrow<class_handle_type<T>>(scope.attr(name));
684 return nb::borrow<class_handle_type<T>>(outer.attr(name));
705 template <
class T,
auto Ctors,
bool HasDefault,
bool Aggregate,
bool Copyable,
708 if constexpr (HasDefault)
709 cls.def(nb::init<>());
710 if constexpr (Copyable) {
715 std::is_constructible_v<construction_type<T>,
const T&>,
716 "welder: this type's trampoline lacks a copy-from-base "
717 "constructor, so a copied Python-subclass instance would hold a "
718 "plain base payload and silently stop dispatching virtuals into "
719 "Python. The WELDER_PY_TRAMPOLINE(TRAMP, BASE) macro declares "
720 "it; a hand-rolled trampoline needs 'Tramp(const Base&)' — or "
721 "mark::exclude the copy constructor.");
726 cls.def(
"__copy__", [](nb::handle self) {
731 [](nb::handle self, nb::object memo) {
736 template for (
constexpr auto ctor : std::define_static_array(Ctors)) {
738 std::meta::parameters_of(ctor).size()>{});
746 std::make_index_sequence<d>{});
748 if constexpr (Aggregate) {
766 template <std::meta::info Mem,
class Bound>
768 if (!std::meta::is_public(Mem) || std::meta::is_bit_field(Mem))
770 if (std::meta::parent_of(Mem) != ^^Bound)
772 using F = [:std::meta::remove_cv(std::meta::type_of(Mem)):];
773 if (std::meta::is_volatile_type(std::meta::type_of(Mem)))
775 return std::is_arithmetic_v<F> || std::is_enum_v<F> ||
776 std::is_same_v<F, std::string>;
811 std::size_t offset,
bool read_only,
813 auto get = [offset](nb::handle self) -> D {
814 return *
reinterpret_cast<const D*
>(
815 static_cast<const char*
>(nb::inst_ptr<void>(self)) + offset);
817 nb::object get_p{
doc ? nb::cpp_function(get, nb::is_method(),
818 nb::is_getter(),
doc)
819 : nb::cpp_function(get, nb::is_method(),
823 auto set = [offset](nb::handle self, D value) {
824 *
reinterpret_cast<D*
>(
825 static_cast<char*
>(nb::inst_ptr<void>(self)) + offset) =
828 set_p = nb::cpp_function(set, nb::is_method());
830 nb::detail::property_install(cls.ptr(), name, get_p.ptr(), set_p.ptr());
848 template <std::meta::info Mem,
class Style = ::welder::naming::none>
850 constexpr const char* name{
857 constexpr bool read_only{std::meta::is_const_type(std::meta::type_of(Mem)) ||
859 if constexpr (!std::meta::is_public(Mem)) {
865 if constexpr (read_only) {
867 cls.def_prop_ro(name, &fa::get,
868 nb::rv_policy::reference_internal,
doc);
870 cls.def_prop_ro(name, &fa::get,
871 nb::rv_policy::reference_internal);
874 cls.def_prop_rw(name, &fa::get, &fa::set,
875 nb::rv_policy::reference_internal,
doc);
877 cls.def_prop_rw(name, &fa::get, &fa::set,
878 nb::rv_policy::reference_internal);
881 Mem,
typename std::remove_reference_t<
882 decltype(cls)>::Type>) {
883 using F = [:std::meta::remove_cv(std::meta::type_of(Mem)):];
888 static_cast<std::size_t
>(std::meta::offset_of(Mem).bytes),
890 }
else if constexpr (read_only) {
892 cls.def_ro(name, &[:Mem:],
doc);
894 cls.def_ro(name, &[:Mem:]);
897 cls.def_rw(name, &[:Mem:],
doc);
899 cls.def_rw(name, &[:Mem:]);
915 template <
class T, std::meta::info Getter, std::meta::info Setter>
920 auto def{[&](
auto&&... extra) {
921 if constexpr (Setter == std::meta::info{}) {
922 cls.def_prop_ro(name, &[:Getter:],
923 std::forward<
decltype(extra)>(extra)...);
924 }
else if constexpr (std::is_void_v<
925 typename [:std::meta::return_type_of(Setter):]>) {
926 cls.def_prop_rw(name, &[:Getter:], &[:Setter:],
927 std::forward<
decltype(extra)>(extra)...);
933 [:std::meta::type_of(std::meta::parameters_of(Setter)[0]):];
934 static constexpr auto sp{&[:Setter:]};
937 [](T& self, Arg v) { (self.*sp)(std::forward<Arg>(v)); },
938 std::forward<decltype(extra)>(extra)...);
941 constexpr nb::rv_policy rvp{[] {
945 constexpr auto rt{std::meta::return_type_of(Getter)};
946 return std::meta::is_pointer_type(rt) ||
947 std::meta::is_lvalue_reference_type(rt)
948 ? nb::rv_policy::reference_internal
949 : nb::rv_policy::automatic;
960 template <auto Fns,
class Style = ::welder::naming::none>
962 constexpr const char* name{
964 template for (
constexpr auto fn : std::define_static_array(Fns)) {
966 cls.def(std::forward<
decltype(a)>(a)...);
973 fn,
typename std::remove_reference_t<
decltype(cls)>::Type,
976 [&cls](
auto&&... a) {
977 cls.def(std::forward<
decltype(a)>(a)...);
979 std::make_index_sequence<d>{});
984 template <auto Fns,
class Style = ::welder::naming::none>
986 constexpr const char* name{
989 template for (
constexpr auto fn : std::define_static_array(Fns)) {
991 cls.def_static(std::forward<
decltype(a)>(a)...);
997 [&cls](
auto&&... a) {
998 cls.def_static(std::forward<
decltype(a)>(a)...);
1000 std::make_index_sequence<d>{});
1013 template <
class T, auto Fns>
1015 template for (
constexpr auto fn : std::define_static_array(Fns)) {
1022 std::make_index_sequence<
1033 template <
class T, auto Fns, auto Covered>
1036 [&cls](
const char* name,
auto fp) {
1037 cls.def(name, fp, nb::is_operator{});
1043 template <
class T, std::meta::info Fn>
1055 template <std::meta::info Fn,
bool NotImpl,
class Cls, std::size_t... K>
1057 std::index_sequence<K...>) {
1060 constexpr nb::rv_policy rvp{
1063 auto def{[&](
auto&&... extra) {
1065 cls.def(name, &[:Fn:], rvp,
1066 nb::keep_alive<ka[K].nurse, ka[K].patient>()...,
1067 std::forward<
decltype(extra)>(extra)...);
1069 cls.def(name, &[:Fn:],
doc.c_str(), rvp,
1070 nb::keep_alive<ka[K].nurse, ka[K].patient>()...,
1071 std::forward<
decltype(extra)>(extra)...);
1073 if constexpr (NotImpl)
1074 def(nb::is_operator{});
1082 template <
class T, std::meta::info Fn>
1085 if constexpr (name !=
nullptr) {
1087 using Lhs =
typename
1088 [:std::meta::type_of(std::meta::parameters_of(Fn)[0]):];
1091 [](
const T& self, Lhs lhs) {
1092 return [:Fn:](
static_cast<Lhs&&
>(lhs), self);
1110 const ::welder::detail::enum_doc& ed) {
1116 const std::string
doc{DocStyle::format_enum(ed)};
1118 return nb::enum_<E>(m, name,
doc.c_str(), nb::is_arithmetic());
1119 return nb::enum_<E>(m, name, nb::is_arithmetic());
1129 const ::welder::detail::enum_doc& ed) {
1130 const std::string
doc{DocStyle::format_enum(ed)};
1132 return nb::enum_<E>(outer_cls, name,
doc.c_str(), nb::is_arithmetic());
1133 return nb::enum_<E>(outer_cls, name, nb::is_arithmetic());
1137 template <std::meta::info Enum,
class Style = ::welder::naming::none>
1151 if constexpr (!std::is_scoped_enum_v<E>)
1167 m.attr(
"__doc__") =
doc;
1177 template <auto Fns,
class Style = ::welder::naming::none>
1181 template for (
constexpr auto fn : std::define_static_array(Fns)) {
1183 m.def(std::forward<
decltype(a)>(a)...);
1186 if constexpr (d > 0)
1189 [&m](
auto&&... a) { m.def(std::forward<
decltype(a)>(a)...); },
1190 std::make_index_sequence<d>{});
1192 return m.attr(fn_name);
1201 template <std::meta::info Var,
class Style = ::welder::naming::none>
1203 const char* name_override =
nullptr) {
1207 if constexpr (std::meta::is_const_type(std::meta::type_of(Var))) {
1208 m.attr(name) = [:Var:];
1212 auto property{nb::module_::import_(
"builtins").attr(
"property")};
1213 live[name] = property(
1214 nb::cpp_function([](nb::object) {
return [:Var:]; }),
1215 nb::cpp_function([](nb::object,
1216 typename [:std::meta::type_of(Var):] v) {
1224 return m.def_submodule(name);
1248 template <
class Container,
class Style = ::welder::naming::none>
1250 constexpr ::welder::container_kind kind{
1260 nb::bind_vector<Container, nb::rv_policy::reference_internal>(
1262 using Elem =
typename Container::value_type;
1263 using Size =
typename Container::size_type;
1269 if constexpr (
requires(Container& c, Size n) { c.reserve(n); })
1271 "reserve", [](Container& v, Size n) { v.reserve(n); },
1273 "Pre-allocate capacity for at least n elements (no-op if capacity "
1274 "already exceeds n). Prevents reallocation — and reference "
1275 "invalidation — across a following run of append()/new().");
1279 if constexpr (
requires(Container& c, Size n) { c.resize(n); })
1281 "resize", [](Container& v, Size n) { v.resize(n); },
1283 "Resize to exactly n elements, value-initializing any new tail "
1284 "elements. Shrinking or reallocating invalidates references.");
1293 if constexpr (std::is_class_v<Elem> &&
1294 std::is_default_constructible_v<Elem>) {
1297 [](Container& v) -> Elem& {
return v.emplace_back(); },
1298 nb::rv_policy::reference_internal,
1299 "Default-construct a new element in place at the end and return "
1300 "a live reference to it.");
1311 nb::bind_map<Container, nb::rv_policy::reference_internal>(m, name);
1330 template <
class Container>
1332 using Elem =
typename Container::value_type;
1333 constexpr std::size_t N{std::tuple_size_v<Container>};
1334 constexpr nb::rv_policy P{nb::rv_policy::reference_internal};
1335 auto cls{nb::class_<Container>(m, name)};
1336 cls.def(nb::init<>(),
"Default constructor")
1337 .def(nb::init<const Container&>(),
"Copy constructor")
1338 .def(
"__len__", [](
const Container&) {
return N; })
1339 .def(
"__bool__", [](
const Container&) {
return N != 0; })
1343 return nb::make_iterator<P>(nb::type<Container>(),
"Iterator",
1344 a.begin(), a.end());
1346 nb::keep_alive<0, 1>())
1349 [](Container& a, Py_ssize_t i) -> Elem& {
1353 .def(
"__setitem__", [](Container& a, Py_ssize_t i,
const Elem& v) {
1360 [](Container* self, nb::typed<nb::iterable, Elem> seq) {
1364 Container* a{
new (self) Container{}};
1367 for (nb::handle h : seq) {
1369 throw nb::value_error(
1370 "expected a sequence of the array's fixed length");
1371 (*a)[i++] = nb::cast<Elem>(h);
1374 throw nb::value_error(
1375 "expected a sequence of the array's fixed length");
1381 "Construct from a length-N iterable");
1382 nb::implicitly_convertible<nb::iterable, Container>();
1392 template <
class Container,
class Cls>
1394 using Elem =
typename Container::value_type;
1396 std::is_arithmetic_v<Elem> && !std::is_same_v<Elem, bool>) {
1402 [](Container& v, nb::handle, nb::handle) {
1403 return nb::ndarray<nb::numpy, Elem, nb::ndim<1>, nb::c_contig>(
1404 v.data(), {v.size()}, nb::find(&v));
1406 nb::arg(
"dtype") = nb::none(), nb::arg(
"copy") = nb::none());
1422 i +=
static_cast<Py_ssize_t
>(n);
1423 if (i < 0 ||
static_cast<std::size_t
>(i) >= n)
1424 throw nb::index_error(
"array index out of range");
1425 return static_cast<std::size_t
>(i);
1433 template <
class Container,
class Elem,
class Cls>
1436 cls.def_prop_ro(
"__array_interface__", [](Container& v) {
1437 static constexpr auto d{pyai::ai_descr<^^Elem>()};
1439 for (
auto [nm, ts] : d)
1440 descr.append(nb::make_tuple(nm, ts));
1442 out[
"shape"] = nb::make_tuple(v.size());
1443 out[
"typestr"] = pyai::ai_typestr<Elem>();
1444 out[
"descr"] = descr;
1445 out[
"data"] = nb::make_tuple(
1446 reinterpret_cast<std::uintptr_t
>(v.data()),
false);
1454 if (live.size() != 0)
1459static_assert(::welder::rod<rod<>>,
1460 "welder::rods::nanobind::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 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.
@ 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.
nb::module_ module_type
nanobind's module handle.
static void _def_aggregate_init(auto &cls, std::index_sequence< I... >)
Synthesize a field constructor for a baseless aggregate T.
static void _def_init(auto &cls, std::index_sequence< I... >)
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 (...
static consteval nb::rv_policy _rv_policy(::welder::rv_kind k)
Map welder's neutral welder::rv_kind to nanobind's rv_policy.
static consteval const char * special_method_name(std::meta::info op_fn)
Map a member operator to its Python dunder (nullptr = not exposed).
static void _def_function(const char *name, Def def_into)
Convenience overload: derive the parameter and keep_alive index sequences from Fn.
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 ....
nb::enum_< E > enum_handle_type
The enum handle make_enum yields — exactly its return type.
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 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 ...
static constexpr lang language
welder::lang::py.
static void _numpy_view(Cls &cls)
Give contiguous sequence class cls the zero-copy NumPy view its element type supports: an __array__ r...
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 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).
static constexpr bool _erasable_field
Whether Mem can bind through the class-ERASED field path (see _def_erased_field): a public,...
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 void set_module_doc(module_type &m, const char *doc)
Set the (sub)module docstring.
static void add_enumerator(auto &e)
Add enumerator Enum to the enum handle.
static void add_comparisons(auto &cls)
Synthesize the relational dunders from operator<=> group Fns via rewritten expressions (a < b,...
static void add_operator(auto &cls)
Bind operator slot group Fns — one (operator, arity) slot whole, member and anchored free entries mix...
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 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.
static void add_constructors(auto &cls)
Bind T's whole constructor set (a chained-def framework just loops it): the default constructor when ...
static void _def_reflected_operator(auto &cls)
Bind reflected free operator Fn (T is its right operand) under its reflected dunder,...
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 void add_method(auto &cls)
Bind method overload group Fns (name from Fns[0]; nanobind chains one .def per overload and dispatche...
static void add_variable(module_type &m, nb::dict &live, const char *name_override=nullptr)
Bind namespace variable Var as a module attribute.
static void close_module(module_type &m, nb::dict &live)
Close the session: apply any accumulated live properties.
static void _install_live_properties(nb::module_ &m, nb::dict props)
Give module m live get/set semantics for the names in props.
static void add_stringifier(auto &cls)
Bind the swept free ostream inserter Fn as __str__ (via welder::detail::stringify).
static consteval auto _styled_param_names()
Register the function/method reflected by Fn onto a nanobind target.
static void _def_function(const char *name, Def def_into, std::index_sequence< I... >, std::index_sequence< K... >)
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_cla...
static void add_static_method(auto &cls)
Bind static-method overload group Fns.
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; ...
static void finish_enum(auto &e)
Finalize enum E: export an unscoped enum's values into the enclosing scope.
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 constexpr bool has_native_caster
caster_oracle: T is convertible without welder registering a class for it iff nanobind does not fall ...
decltype(make_class< T, std::array< std::meta::info, 0 >{}>( std::declval< module_type & >(), nullptr, nullptr, std::index_sequence<>{})) class_handle_type
The class handle make_class yields for T — exactly its return type for a base-less T (so it captures ...
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 _array_interface(Cls &cls)
Give the opaque std::vector<Elem> class cls a __array_interface__ property — the numpy array-interfac...
static nb::object _copy_instance(nb::handle self, nb::object *memo)
The subclass-faithful engine behind __copy__/__deepcopy__.
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 — Pytho...
static nb::dict open_module(module_type &)
Open a per-module session: a dict accumulating live (mutable-variable) properties; _install_live_prop...
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 field constructor's parameter type for field I of T: the field type itself,...
static consteval bool _lazy_default()
Whether field I of aggregate T binds its NSDMI default LAZILY: true for a defaultable field whose typ...
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++...
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 o...
static void _def_init_truncations(auto &cls, std::index_sequence< K... >)
Register nb::init<P0, P1, …>() for constructor Ctor.
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...
static constexpr bool _needs_registration
Whether nanobind can only convert T via runtime class registration.
[:::welder::rods::python::construction_type_of< T >() :] construction_type
The type welder constructs when binding T — its registered trampoline if one exists,...
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...
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 .
Virtual-function overriding support shared by welder's Python backends.
welder's binding entry point: the welder::welder struct.