49#include <nanobind/nanobind.h>
76template <::welder::doc_style DocStyle = ::welder::rods::python::google_style>
118 std::is_enum_v<std::remove_cvref_t<T>> ||
119 nb::detail::is_base_caster_v<nb::detail::make_caster<T>>;
128 case ::welder::rv_kind::automatic:
return nb::rv_policy::automatic;
129 case ::welder::rv_kind::automatic_reference:
return nb::rv_policy::automatic_reference;
130 case ::welder::rv_kind::take_ownership:
return nb::rv_policy::take_ownership;
131 case ::welder::rv_kind::copy:
return nb::rv_policy::copy;
132 case ::welder::rv_kind::move:
return nb::rv_policy::move;
133 case ::welder::rv_kind::reference:
return nb::rv_policy::reference;
134 case ::welder::rv_kind::reference_internal:
return nb::rv_policy::reference_internal;
135 case ::welder::rv_kind::none:
return nb::rv_policy::none;
137 return nb::rv_policy::automatic;
157 template <std::meta::info Fn,
class Def, std::size_t... I, std::size_t... K>
159 std::index_sequence<I...>, std::index_sequence<K...>) {
167 def_into(name, &[:Fn:], nb::arg(names[I])..., rvp,
168 nb::keep_alive<ka[K].nurse, ka[K].patient>()...);
170 def_into(name, &[:Fn:],
doc.c_str(), nb::arg(names[I])..., rvp,
171 nb::keep_alive<ka[K].nurse, ka[K].patient>()...);
174 def_into(name, &[:Fn:], rvp,
175 nb::keep_alive<ka[K].nurse, ka[K].patient>()...);
177 def_into(name, &[:Fn:],
doc.c_str(), rvp,
178 nb::keep_alive<ka[K].nurse, ka[K].patient>()...);
184 template <std::meta::info Fn,
class Def>
188 std::make_index_sequence<std::meta::parameters_of(Fn).size()>{},
189 std::make_index_sequence<
200 template <std::meta::info Ctor, std::size_t... I>
201 static void _def_init(
auto& cls, std::index_sequence<I...>) {
205 cls.def(nb::init<
typename [:params[I]:]...>(), nb::arg(names[I])...);
207 cls.def(nb::init<
typename [:params[I]:]...>());
221 template <
class T, std::size_t... I>
226 [](T* self,
typename [:std::meta::type_of(fields[I]):]... args) {
227 new (self) T{std::move(args)...};
229 nb::arg(std::define_static_string(
230 std::meta::identifier_of(fields[I])))...);
248 auto builtins{nb::module_::import_(
"builtins")};
249 auto subclass{builtins.attr(
"type")(
250 nb::str(
"welder_live_module"),
251 nb::make_tuple(m.attr(
"__class__")), props)};
256 subclass.attr(
"__module__") = m.attr(
"__name__");
257 m.attr(
"__class__") = subclass;
275 template <
class T,
class Trampoline,
auto Bases, std::size_t... I>
277 std::index_sequence<I...>) {
278 if constexpr (std::is_void_v<Trampoline>) {
280 return nb::class_<T,
typename [:Bases[I]:]...>(scope, name,
doc);
281 return nb::class_<T,
typename [:Bases[I]:]...>(scope, name);
287 return nb::class_<T, Trampoline,
typename [:Bases[I]:]...>(scope, name,
doc);
288 return nb::class_<T, Trampoline,
typename [:Bases[I]:]...>(scope, name);
296 template <
class T,
auto Bases, std::size_t... I>
298 const char*
doc, std::index_sequence<I...> seq) {
300 if constexpr (py::has_virtual_methods(^^T)) {
303 constexpr auto scanned{py::scanned_trampoline_of(^^T)};
305 py::trampoline_for<T> != std::meta::info{} || !scanned.ambiguous,
306 "welder: more than one [[=welder::rods::python::trampoline]] class in "
307 "this namespace derives from T; disambiguate by specializing "
308 "welder::rods::python::trampoline_for<T>.");
309 constexpr std::meta::info tramp{py::trampoline_for<T> != std::meta::info{}
310 ? py::trampoline_for<T>
312 if constexpr (tramp != std::meta::info{}) {
313 using Trampoline = [:tramp:];
315 py::trampoline_covers(^^T, ^^Trampoline),
316 "welder: the trampoline registered for this type does not "
317 "override all of its virtual methods; every virtual needs an "
318 "override forwarding to Python (see WELDER_PY_OVERRIDE).");
323 "welder: this welded type has virtual methods but no trampoline "
324 "is registered, so a Python subclass could not override them. "
325 "Register one — a [[=welder::rods::python::trampoline]] subclass "
326 "in T's namespace, or a welder::rods::python::trampoline_for<T> "
327 "specialization — or annotate T with "
328 "[[=welder::rods::python::bind_flat]] to bind it non-overridably.");
348 return ::welder::rods::python::operator_dunder(op_fn);
370 template <
class T,
auto Bases, std::size_t... I>
372 std::index_sequence<I...> seq) {
381 template <
class T,
auto Bases, std::size_t... I>
383 const char*
doc, std::index_sequence<I...> seq) {
395 std::declval<module_type&>(),
nullptr,
nullptr, std::index_sequence<>{}));
402 template <
class T, auto Ctors,
bool HasDefault,
bool Aggregate>
404 if constexpr (HasDefault)
405 cls.def(nb::init<>());
406 template for (
constexpr auto ctor : std::define_static_array(Ctors)) {
408 std::meta::parameters_of(ctor).size()>{});
410 if constexpr (Aggregate) {
425 template <std::meta::info Mem,
class Style = ::welder::naming::none>
427 constexpr const char* name{
430 if constexpr (!std::meta::is_public(Mem)) {
436 if constexpr (std::meta::is_const_type(std::meta::type_of(Mem))) {
438 cls.def_prop_ro(name, &fa::get,
439 nb::rv_policy::reference_internal,
doc);
441 cls.def_prop_ro(name, &fa::get,
442 nb::rv_policy::reference_internal);
445 cls.def_prop_rw(name, &fa::get, &fa::set,
446 nb::rv_policy::reference_internal,
doc);
448 cls.def_prop_rw(name, &fa::get, &fa::set,
449 nb::rv_policy::reference_internal);
451 }
else if constexpr (std::meta::is_const_type(std::meta::type_of(Mem))) {
454 cls.def_ro(name, &[:Mem:],
doc);
456 cls.def_ro(name, &[:Mem:]);
459 cls.def_rw(name, &[:Mem:],
doc);
461 cls.def_rw(name, &[:Mem:]);
467 template <auto Fns,
class Style = ::welder::naming::none>
469 constexpr const char* name{
471 template for (
constexpr auto fn : std::define_static_array(Fns)) {
473 cls.def(std::forward<
decltype(a)>(a)...);
479 template <auto Fns,
class Style = ::welder::naming::none>
481 constexpr const char* name{
484 template for (
constexpr auto fn : std::define_static_array(Fns)) {
486 cls.def_static(std::forward<
decltype(a)>(a)...);
496 template for (
constexpr auto fn : std::define_static_array(Fns)) {
498 cls.def(std::forward<
decltype(a)>(a)...);
516 return nb::enum_<E>(m, name,
doc, nb::is_arithmetic());
517 return nb::enum_<E>(m, name, nb::is_arithmetic());
528 return nb::enum_<E>(outer_cls, name,
doc, nb::is_arithmetic());
529 return nb::enum_<E>(outer_cls, name, nb::is_arithmetic());
533 template <std::meta::info Enum,
class Style = ::welder::naming::none>
547 if constexpr (!std::is_scoped_enum_v<E>)
563 m.attr(
"__doc__") =
doc;
573 template <auto Fns,
class Style = ::welder::naming::none>
577 template for (
constexpr auto fn : std::define_static_array(Fns)) {
579 m.def(std::forward<
decltype(a)>(a)...);
582 return m.attr(fn_name);
591 template <std::meta::info Var,
class Style = ::welder::naming::none>
593 const char* name_override =
nullptr) {
597 if constexpr (std::meta::is_const_type(std::meta::type_of(Var))) {
598 m.attr(name) = [:Var:];
602 auto property{nb::module_::import_(
"builtins").attr(
"property")};
603 live[name] = property(
604 nb::cpp_function([](nb::object) {
return [:Var:]; }),
605 nb::cpp_function([](nb::object,
606 typename [:std::meta::type_of(Var):] v) {
614 return m.def_submodule(name);
619 if (live.size() != 0)
624static_assert(::welder::rod<rod<>>,
625 "welder::rods::nanobind::rod<> must satisfy welder::rod");
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...
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...
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.
@ 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...
@ static_method
a static member function → transform_static_method.
@ function
a free function → transform_function.
consteval void validate_return_policy()
Reject a return_policy on Fn (for language L) that contradicts Fn's return type.
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...
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 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 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 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 add_constructors(auto &cls)
Bind the default constructor.
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 _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.
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_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 _def_function(const char *name, Def def_into)
Convenience overload: derive the parameter and keep_alive index sequences from Fn.
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 _def_init(auto &cls, std::index_sequence< I... >)
Register nb::init<P0, P1, …>() for constructor Ctor.
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 void add_operator(auto &cls)
Bind operator overload group Fns under its Python dunder (one operator + arity per group,...
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 — Pytho...
static void finish_enum(auto &e)
Finalize enum E: export an unscoped enum's values into the enclosing scope.
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 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).
static nb::dict open_module(module_type &)
Open a per-module session: a dict accumulating live (mutable-variable) properties; _install_live_prop...
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,...
Virtual-function overriding support shared by welder's Python backends.
welder's binding entry point: the welder::welder struct.