welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
welder::rod Concept Reference

The contract a rod (a welder backend, welder::rods::…::rod) must satisfy to plug into the generic driver. More...

#include <welder/concepts.hpp>

Concept definition

template<class B>
concept rod =
requires {
{ B::language } -> std::convertible_to<lang>;
typename B::module_type;
} &&
requires(typename B::module_type& m, const char* s,
std::remove_cvref_t<decltype(B::open_module(
std::declval<typename B::module_type&>()))> session) {
{ B::open_module(m) };
{ B::add_submodule(m, s) } -> std::same_as<typename B::module_type>;
B::set_module_doc(m, s);
B::close_module(m, session);
{ B::special_method_name(^^int) } -> std::convertible_to<const char*>;
B::template add_function<std::array<std::meta::info, 1>{^^int},
B::template add_variable<^^int, detail::any_type>(m, session);
} &&
requires(typename B::template class_handle_type<detail::any_type>& cls,
typename B::template enum_handle_type<detail::any_enum>& en) {
B::template add_constructors<detail::any_type,
std::array<std::meta::info, 0>{}, false,
false>(cls);
B::template add_field<^^int, detail::any_type>(cls);
B::template add_method<std::array<std::meta::info, 1>{^^int},
B::template add_static_method<std::array<std::meta::info, 1>{^^int},
B::template add_operator<std::array<std::meta::info, 1>{^^int}>(cls);
B::template add_enumerator<^^int, detail::any_type>(en);
B::template finish_enum<detail::any_enum>(en);
}
The one bindability fact a backend must provide: can it natively convert a type without welder regist...
Definition concepts.hpp:86
The contract a rod (a welder backend, welder::rods::…::rod) must satisfy to plug into the generic dri...
Definition concepts.hpp:206
A placeholder class type for shape-probing a member template inside a concept.
Definition concepts.hpp:51

Detailed Description

The contract a rod (a welder backend, welder::rods::…::rod) must satisfy to plug into the generic driver.

A rod B is a stateless struct; nothing is inherited, and every member is static. The concept shape-checks almost the whole contract — the associated types, the module/session machinery, and every emission hook — so a rod that omits or mis-signs one fails here with a clear "not a `welder::rod`" rather than a deep error the first time the driver instantiates it. The templated hooks can't be quantified over every type/reflection, so — as welder::caster_oracle probes has_native_caster — they are probed once with fixed placeholders (welder::detail::any_type, welder::detail::any_enum, ^^int), checking shape (the hook exists with a compatible signature), not per-type correctness. The per-class / per-enum hooks are probed against the rod's own declared handle types (class_handle_type / enum_handle_type); every emission hook returns void, so only signatures are substituted and no hook body is instantiated.

Note
The one gap: the factories themselves. make_class and make_enum return auto, so merely naming them in a requirement would force their bodies to be instantiated to deduce the return type — and a rod's make_class legitimately does real work there (the sol2 rod registers a type's constructors inside it), which a placeholder type does not survive. So the two factories stay contract-by-documentation**, enforced when the driver instantiates the rod over a real welded type. The concept sidesteps them by requiring the handle types as associated aliases* (class_handle_type<T> / enum_handle_type<E> — what the factories yield) rather than deducing them from a factory call, which is what lets the per-handle hooks be checked without instantiating any factory body.

Associated:**

static constexpr lang language; // the target language B binds to
using module_type = ...; // B's module handle (passed by ref)
template <class T> static constexpr bool has_native_caster; // caster_oracle
template <class T> using class_handle_type = ...; // what make_class yields for T
template <class E> using enum_handle_type = ...; // what make_enum yields for E
lang
The target languages welder ships rods for — but not the whole value space.
Definition lang.hpp:42

Type binding** (the class handle is class_handle_type<T>, what make_class returns). The per-member hooks take a trailing class Style (a welder::naming::name_style) so the rod resolves its own name via welder::name_of<Mem, language, Style, ent_kind::…>() — which also applies any [[=welder::weld_as]] override. The class name is styled by the driver and passed to make_class ready-made.

Callables arrive as whole overload groups — an auto Fns non-type argument, a std::array<std::meta::info, N> (N ≥ 1, declaration order) of overloads that share one target name. The CARRIAGE computes the group from its resolution and gates every member; the rod only emits — a chained-def framework (pybind11) loops the group, a one-value-per-name framework (the Lua rods) registers it as one overload set. The group's name resolves from Fns[0]. Constructors arrive the same way, as one add_constructors call carrying the participating constructor reflections plus the two carriage-computed synthesized forms (the default constructor — decided against construction_type<T> where the rod nominates one — and the aggregate field constructor):

template <class T, auto Bases, std::size_t... I>
static auto make_class(module_type&, const char* name, const char* doc,
std::index_sequence<I...>); // Bases[I] spliced
// OPTIONAL (requires-detected): place a NESTED member type under its
// enclosing type's binding. The carriage prefers these for a class-scoped
// type (the outer class handle is the registration scope — Python:
// module.Outer.Inner); a rod without them falls back to the module-scope
// factories above, i.e. flat placement under the type's resolved name.
template <class T, auto Bases, std::size_t... I>
static auto make_nested_class(module_type&, auto& outer_cls, const char* name,
const char* doc, std::index_sequence<I...>);
// OPTIONAL, preferred over the plain form when declared: the
// declaring-entity-aware nested factory. Decl is ^^T, or the MEMBER ALIAS
// an (unnameable) template specialization was registered through — the one
// C++-spellable name such a target has, which a text-emitting rod needs.
template <class T, std::meta::info Decl, auto Bases, std::size_t... I>
static auto make_nested_class(module_type&, auto& outer_cls, const char* name,
const char* doc, std::index_sequence<I...>);
template <class E>
static auto make_nested_enum(module_type&, auto& outer_cls, const char* name,
const char* doc);
// OPTIONAL: called after a nested class's whole interior has registered
// (innermost-first). For a rod whose class handle re-opens the class by
// name/path (LuaBridge3), this is where the class table actually moves
// under the outer — moving it at creation would break the re-opens.
template <class T>
static void finish_nested_class(module_type&, auto& outer_cls, auto& cls,
const char* name);
template <class T, auto Ctors, bool HasDefault, bool Aggregate>
static void add_constructors(auto& cls); // the whole participating set
template <std::meta::info Mem, class Style> static void add_field(auto& cls);
template <auto Fns, class Style> static void add_method(auto& cls);
template <auto Fns, class Style> static void add_static_method(auto& cls);
template <auto Fns> static void add_operator(auto& cls); // fixed op name
static consteval const char* special_method_name(std::meta::info op_fn);
// target special-method name for a member operator, or nullptr if the
// backend does not expose it (drives add_operator eligibility)
consteval detail::doc_spec< N > doc(const char(&s)[N])
Attach a docstring to a namespace, class, function, or function parameter.

Enum binding** (the enum handle is whatever make_enum returns; deduced):

template <class E> static auto make_enum(module_type&, const char* name,
const char* doc);
template <std::meta::info Enum, class Style> static void add_enumerator(auto& e);
template <class E> static void finish_enum(auto& e); // e.g. export unscoped

Namespace / module binding** (a "session" is backend scratch state — e.g. an accumulator for deferred, batched attributes — obtained per (sub)module):

static auto open_module(module_type&); // -> session
static void set_module_doc(module_type&, const char* doc);
template <auto Fns, class Style> static void add_function(module_type&, const char* name = nullptr);
// a free-function overload group (array NTTP, like add_method)
template <std::meta::info Var, class Style> static void add_variable(module_type&, session&, const char* name = nullptr);
static module_type add_submodule(module_type&, const char* name); // name pre-styled
static void close_module(module_type&, session&); // finalize the session
Template Parameters
Bthe candidate rod type.

Definition at line 206 of file concepts.hpp.