42#include <pybind11/pybind11.h>
43#include <pybind11/native_enum.h>
70template <::welder::doc_style DocStyle = ::welder::rods::python::google_style>
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>>;
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;
142 return py::return_value_policy::automatic;
162 template <std::meta::info Fn,
class Def, std::size_t... I, std::size_t... K>
164 std::index_sequence<I...>, std::index_sequence<K...>) {
170 "welder: return_policy 'none' has no pybind11 equivalent "
171 "(it is nanobind-only) — choose another policy");
176 def_into(name, &[:Fn:], py::arg(names[I])..., rvp,
177 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
179 def_into(name, &[:Fn:],
doc.c_str(), py::arg(names[I])..., rvp,
180 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
183 def_into(name, &[:Fn:], rvp,
184 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
186 def_into(name, &[:Fn:],
doc.c_str(), rvp,
187 py::keep_alive<ka[K].nurse, ka[K].patient>()...);
193 template <std::meta::info Fn,
class Def>
197 std::make_index_sequence<std::meta::parameters_of(Fn).size()>{},
198 std::make_index_sequence<
209 template <std::meta::info Ctor, std::size_t... I>
210 static void _def_init(
auto& cls, std::index_sequence<I...>) {
214 cls.def(py::init<
typename [:params[I]:]...>(), py::arg(names[I])...);
216 cls.def(py::init<
typename [:params[I]:]...>());
228 template <
class T, std::size_t... I>
231 cls.def(py::init([](
typename [:std::meta::type_of(fields[I]):]... args) {
232 return T{std::move(args)...};
234 py::arg(std::define_static_string(
235 std::meta::identifier_of(fields[I])))...);
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)};
264 subclass.attr(
"__module__") = m.attr(
"__name__");
265 m.attr(
"__class__") = subclass;
281 template <
class T,
class Trampoline,
auto Bases, std::size_t... I>
283 std::index_sequence<I...>) {
284 if constexpr (std::is_void_v<Trampoline>) {
286 return py::class_<T,
typename [:Bases[I]:]...>(scope, name,
doc);
287 return py::class_<T,
typename [:Bases[I]:]...>(scope, name);
292 return py::class_<T, Trampoline,
typename [:Bases[I]:]...>(scope, name,
doc);
293 return py::class_<T, Trampoline,
typename [:Bases[I]:]...>(scope, name);
306 template <
class T,
auto Bases, std::size_t... I>
308 const char*
doc, std::index_sequence<I...> seq) {
310 if constexpr (py_::has_virtual_methods(^^T)) {
313 constexpr auto scanned{py_::scanned_trampoline_of(^^T)};
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>
322 if constexpr (tramp != std::meta::info{}) {
323 using Trampoline = [:tramp:];
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).");
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.");
358 return ::welder::rods::python::operator_dunder(op_fn);
380 template <
class T,
auto Bases, std::size_t... I>
382 std::index_sequence<I...> seq) {
391 template <
class T,
auto Bases, std::size_t... I>
393 const char*
doc, std::index_sequence<I...> seq) {
401 template <
class T, auto Ctors,
bool HasDefault,
bool Aggregate>
403 if constexpr (HasDefault)
404 cls.def(py::init<>());
405 template for (
constexpr auto ctor : std::define_static_array(Ctors)) {
407 std::meta::parameters_of(ctor).size()>{});
409 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_property_readonly(
439 name, &fa::get, py::return_value_policy::reference_internal,
442 cls.def_property_readonly(
444 py::return_value_policy::reference_internal);
447 cls.def_property(name, &fa::get, &fa::set,
448 py::return_value_policy::reference_internal,
451 cls.def_property(name, &fa::get, &fa::set,
452 py::return_value_policy::reference_internal);
454 }
else if constexpr (std::meta::is_const_type(std::meta::type_of(Mem))) {
457 cls.def_readonly(name, &[:Mem:],
doc);
459 cls.def_readonly(name, &[:Mem:]);
462 cls.def_readwrite(name, &[:Mem:],
doc);
464 cls.def_readwrite(name, &[:Mem:]);
470 template <auto Fns,
class Style = ::welder::naming::none>
472 constexpr const char* name{
474 template for (
constexpr auto fn : std::define_static_array(Fns)) {
476 cls.def(std::forward<
decltype(a)>(a)...);
482 template <auto Fns,
class Style = ::welder::naming::none>
484 constexpr const char* name{
487 template for (
constexpr auto fn : std::define_static_array(Fns)) {
489 cls.def_static(std::forward<
decltype(a)>(a)...);
499 template for (
constexpr auto fn : std::define_static_array(Fns)) {
501 cls.def(std::forward<
decltype(a)>(a)...);
525 std::unique_ptr<py::native_enum<E>>
impl;
544 scope.attr(
name).attr(
"__pybind11_native_enum__") =
true;
558 std::declval<module_type&>(),
nullptr,
nullptr, std::index_sequence<>{}));
569 std::make_unique<py::native_enum<E>>(m, name,
"enum.IntEnum",
579 const char* name,
const char*
doc) {
580 return {outer_cls, name,
581 std::make_unique<py::native_enum<E>>(outer_cls, name,
587 template <std::meta::info Enum,
class Style = ::welder::naming::none>
601 if constexpr (!std::is_scoped_enum_v<E>)
623 template <auto Fns,
class Style = ::welder::naming::none>
627 template for (
constexpr auto fn : std::define_static_array(Fns)) {
629 m.def(std::forward<
decltype(a)>(a)...);
632 return m.attr(fn_name);
641 template <std::meta::info Var,
class Style = ::welder::naming::none>
643 const char* name_override =
nullptr) {
647 if constexpr (std::meta::is_const_type(std::meta::type_of(Var))) {
648 m.attr(name) = [:Var:];
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) {
664 return m.def_submodule(name);
669 if (live.size() != 0)
674static_assert(::welder::rod<rod<>>,
675 "welder::rods::pybind11::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...
@ none
Do not convert (nanobind rv_policy::none); pybind11 has no equivalent.
@ 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...
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).
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 finish_enum(auto &e)
Finalize enum E: export an unscoped enum's values into the enclosing scope, then commit the enum to t...
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_operator(auto &cls)
Bind operator overload group Fns under its Python dunder (one operator + arity per group,...
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_function(const char *name, Def def_into)
Convenience overload: derive the parameter and keep_alive index sequences from Fn.
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 set_module_doc(module_type &m, const char *doc)
Set the (sub)module docstring.
static void add_constructors(auto &cls)
Bind T's whole constructor set (a chained-def framework just loops it): the default constructor when ...
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.
py::module_ module_type
pybind11's module handle.
static void close_module(module_type &m, py::dict &live)
Close the session: apply any accumulated live properties.
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...
static void _def_init(auto &cls, std::index_sequence< I... >)
Register py::init<P0, P1, …>() for constructor Ctor.
[:::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 ....
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).
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 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 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 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...
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.