welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
rod.hpp
Go to the documentation of this file.
1#pragma once
67#include <array>
68#include <cstddef>
69#include <functional>
70#include <meta>
71#include <type_traits>
72#include <utility>
73#include <vector>
74
75#include <welder/welder.hpp> // welder::welder + rod contract + driver
76#include <welder/rods/lua/sol2/metamethods.hpp> // operator -> sol2 metamethod map
77#include <welder/bind_traits.hpp> // aggregate_* helpers
78
79#include <sol/sol.hpp>
80
81namespace welder::inline v0::rods::sol2 {
82
83// Note: the namespace is `welder::rods::sol2`; the library namespace is `::sol`. They do
84// not collide, so `sol::` below refers to the library without an alias (unlike the
85// Python backends, whose namespace shadowed the library's).
86
89template <class T, class... A>
90using ctor_sig = T(A...);
91
103struct rod {
104 static constexpr lang language{lang::lua};
105 using module_type = ::sol::table;
106
116 struct session {
117 ::sol::table getters{};
118 ::sol::table setters{};
119 bool has_live{false};
120 };
121
122 protected:
123 // --- implementation helpers (not part of the welder::rod contract) --
124
150 template <class T>
151 static constexpr bool _needs_registration =
152 std::is_enum_v<std::remove_cvref_t<T>> ||
153 ::sol::lua_type_of<std::remove_cvref_t<T>>::value == ::sol::type::userdata;
154
163 template <class E>
165 ::sol::table values;
166 std::function<void(const char*, lua_Integer)>
168 bool scoped;
169 };
170
187 template <class T, auto Ctors, bool HasDefault, bool Aggregate>
188 static consteval std::vector<std::meta::info> _ctor_signatures() {
189 std::vector<std::meta::info> sigs;
190 auto sig = [](std::vector<std::meta::info> targs) {
191 return std::meta::dealias(std::meta::substitute(^^ctor_sig, targs));
192 };
193 if (HasDefault)
194 sigs.push_back(sig({^^T}));
195 for (auto c : Ctors) {
196 std::vector<std::meta::info> targs{^^T};
197 for (auto p : std::meta::parameters_of(c))
198 targs.push_back(std::meta::type_of(p));
199 sigs.push_back(sig(targs));
200 }
201 // constexpr-if: the branch indexes the field array, which must not be
202 // instantiated for a fieldless type (the array<info, 0> trap) — and
203 // Aggregate guarantees at least one field.
204 if constexpr (Aggregate) {
205 // One arity per omissible NSDMI-suffix tail (aggregate_required_arity):
206 // C++26 parenthesized aggregate init fills omitted trailing fields
207 // from their NSDMIs, so T(prefix…) is valid for every prefix length
208 // down to the required arity. Arity 0 would duplicate the default
209 // constructor's signature, so it starts at 1 when that is bound.
212 if (HasDefault && start == 0)
213 start = 1;
214 for (std::size_t arity{start}; arity <= fields.size(); ++arity) {
215 std::vector<std::meta::info> targs{^^T};
216 for (std::size_t i{0}; i < arity; ++i)
217 targs.push_back(std::meta::type_of(fields[i]));
218 sigs.push_back(sig(targs));
219 }
220 }
221 return sigs;
222 }
223
225 template <class T, auto Ctors, bool HasDefault, bool Aggregate>
226 static consteval auto _ctor_sigs_array() {
227 constexpr std::size_t n{
229 std::array<std::meta::info, n> out{};
230 // Guard the fill: std::array<T, 0>::operator[] is not consteval, so it must
231 // not be instantiated for a type with no exposed constructors.
232 if constexpr (n != 0) {
234 for (std::size_t i{0}; i < n; ++i)
235 out[i] = v[i];
236 }
237 return out;
238 }
239
246 template <class T, auto Sigs, std::size_t... I>
247 static void _set_constructors(::sol::usertype<T>& ut,
248 std::index_sequence<I...>) {
249 // Expose both the call form `T(…)` and the idiomatic `T.new(…)`.
250 ut[::sol::call_constructor] = ::sol::constructors<typename [:Sigs[I]:]...>();
251 ut["new"] = ::sol::constructors<typename [:Sigs[I]:]...>();
252 }
253
254
266 template <class T, auto Bases, std::size_t... I>
267 static auto _make_usertype(::sol::table& m, const char* name,
268 std::index_sequence<I...>) {
269 // sol2's "automagic" enrollment would auto-register metamethods straight
270 // off the C++ type (SFINAE-detected operator==/</<=, operator(), the
271 // ostream inserter) — bypassing welder's resolution, so an excluded or
272 // per-language-scoped operator would leak into Lua anyway. Welder
273 // registers every operator slot itself (add_operator/add_comparisons/
274 // add_stringifier), so those enrollments are switched off; the
275 // default constructor is off too (the real set is installed afterwards
276 // by add_constructors, the driver's one call — this is what
277 // sol::no_constructor achieved before enrollments took its overload
278 // slot). Destructor/pairs/length automagic stay on (welder has no
279 // opinion there).
280 ::sol::automagic_enrollments enroll{};
281 enroll.default_constructor = false;
282 enroll.to_string_operator = false;
283 enroll.call_operator = false;
284 enroll.less_than_operator = false;
285 enroll.less_than_or_equal_to_operator = false;
286 enroll.equal_to_operator = false;
287 ::sol::usertype<T> ut{m.new_usertype<T>(name, enroll)};
288 if constexpr (sizeof...(I) != 0)
289 ut[::sol::base_classes] =
290 ::sol::bases<typename [:Bases[I]:]...>();
291 return ut;
292 }
293
309 static consteval void _collect_welded_bases(
310 std::meta::info type, lang L, std::vector<std::meta::info>& out) {
311 for (auto base : ::welder::public_bases(type)) {
312 const bool welded{::welder::welded_for(base, L)};
313 if (welded) {
314 bool seen{false};
315 for (auto e : out)
316 if (e == base) {
317 seen = true;
318 break;
319 }
320 if (seen)
321 continue;
322 out.push_back(base);
323 }
324 _collect_welded_bases(base, L, out); // descend (into welded bases too)
325 }
326 }
327
331 template <class T>
332 static consteval auto _welded_bases_array() {
333 constexpr std::size_t n{[] {
334 std::vector<std::meta::info> v;
336 return v.size();
337 }()};
338 std::array<std::meta::info, n> out{};
339 // Guard the fill: std::array<T, 0>::operator[] is not consteval.
340 if constexpr (n != 0) {
341 std::vector<std::meta::info> v;
343 for (std::size_t i{0}; i < n; ++i)
344 out[i] = v[i];
345 }
346 return out;
347 }
348
360 template <auto Grp, class Target, std::size_t... I>
361 static void _register_named(Target& t, const char* name,
362 std::index_sequence<I...>) {
363 // sol2 owns a returned object structurally (a value → a Lua-owned
364 // copy/move; a pointer/reference → a non-owning view), so a
365 // [[=welder::return_policy]] has no runtime effect here — but a
366 // self-contradictory one (a reference to a returned temporary) is still
367 // rejected, uniformly with the Python rods.
369 if constexpr (sizeof...(I) == 1)
370 t[name] = &[:Grp[0]:];
371 else
372 t[name] = ::sol::overload(&[:Grp[I]:]...);
373 }
374
381 template <auto Grp, class Target, std::size_t... I>
382 static void _register_operator(Target& t, std::index_sequence<I...>) {
384 constexpr auto slot{operator_mm(Grp[0]).fn};
385 if constexpr (sizeof...(I) == 1)
386 t[slot] = &[:Grp[0]:];
387 else
388 t[slot] = ::sol::overload(&[:Grp[I]:]...);
389 }
390
391 // --- live namespace-variable proxy --------------------------------------
392
396 static ::sol::object _prev_index(::sol::this_state ts, const ::sol::object& prev,
397 const ::sol::table& self, const ::sol::object& key) {
398 if (prev.get_type() == ::sol::type::function)
399 return ::sol::object{prev.as<::sol::function>()(self, key)};
400 if (prev.get_type() == ::sol::type::table)
401 return ::sol::object{prev.as<::sol::table>()[key]};
402 return ::sol::make_object(ts, ::sol::lua_nil);
403 }
404
408 static void _prev_newindex(const ::sol::object& prev, ::sol::table self,
409 const ::sol::object& key, const ::sol::object& value) {
410 if (prev.get_type() == ::sol::type::function) {
411 prev.as<::sol::function>()(self, key, value);
412 return;
413 }
414 if (prev.get_type() == ::sol::type::table) {
415 prev.as<::sol::table>()[key] = value;
416 return;
417 }
418 self.raw_set(key, value);
419 }
420
431 static void _install_live_variables(module_type& m, ::sol::table getters,
432 ::sol::table setters) {
433 lua_State* L{m.lua_state()};
434 ::sol::state_view lua{L};
435 // Fetch any existing metatable via the raw C API: reading it through a
436 // checked sol::table would fail SOL_ALL_SAFETIES_ON when there is none (nil
437 // is not a table). A pre-existing metatable (a prior live-variable install
438 // onto the same table) is reused and chained; otherwise a fresh one is made.
439 m.push(); // [module]
440 const bool had_mt{lua_getmetatable(L, -1) != 0}; // [module, mt?]
441 ::sol::table mt{had_mt ? ::sol::stack::pop<::sol::table>(L)
442 : lua.create_table()};
443 lua_pop(L, 1); // pop [module]
444 // Capture any metamethods to chain (a state-bound nil when absent, so the
445 // fallback helpers can safely query get_type()).
446 ::sol::object prev_index{mt["__index"]};
447 ::sol::object prev_newindex{mt["__newindex"]};
448
449 mt["__index"] = [getters, prev_index](::sol::this_state ts, ::sol::table self,
450 ::sol::object key) -> ::sol::object {
451 ::sol::object g{getters[key]};
452 if (g.get_type() == ::sol::type::function)
453 return ::sol::object{g.as<::sol::function>()()}; // live read of the C++ global
454 return _prev_index(ts, prev_index, self, key);
455 };
456 mt["__newindex"] = [setters, prev_newindex](::sol::table self, ::sol::object key,
457 ::sol::object value) {
458 ::sol::object s{setters[key]};
459 if (s.get_type() == ::sol::type::function) {
460 s.as<::sol::function>()(value); // live write through to the C++ global
461 return; // no rawset: the key stays live
462 }
463 _prev_newindex(prev_newindex, self, key, value);
464 };
465 m[::sol::metatable_key] = mt;
466 }
467
468 public:
469 // --- caster oracle + emission primitives (the welder::rod contract) --
470
475 template <class T> using class_handle_type = ::sol::usertype<T>;
476 template <class E> using enum_handle_type = _enum_binding<E>;
477
482 template <class T>
484
487 static consteval const char* special_method_name(std::meta::info op_fn) {
488 return operator_mm(op_fn).name;
489 }
490
491 // --- class binding ------------------------------------------------------
492
501 template <class T, auto Bases, std::size_t... I>
502 static auto make_class(module_type& m, const char* name, const char* /*doc*/,
503 std::index_sequence<I...> /*seq*/) {
504 constexpr auto bases{_welded_bases_array<T>()};
506 m, name, std::make_index_sequence<bases.size()>{});
507 }
508
519 template <class T, auto Bases, std::size_t... I>
520 static auto make_nested_class(module_type& m, auto& outer, const char* name,
521 const char* doc, std::index_sequence<I...> seq) {
522 auto ut{make_class<T, Bases>(m, name, doc, seq)};
523 outer[name] = ut; // Outer.Inner = the usertype (a lua reference
524 // value registers as a static entry)
525 m[name] = ::sol::lua_nil; // drop the temporary module-scope key
526 return ut;
527 }
528
536 template <class T, auto Ctors, bool HasDefault, bool Aggregate, bool Copyable,
537 class Style = ::welder::naming::none>
538 static void add_constructors(::sol::usertype<T>& ut) {
540 if constexpr (sigs.size() != 0)
541 _set_constructors<T, sigs>(ut, std::make_index_sequence<sigs.size()>{});
542 }
543
551 template <std::meta::info Mem, class Style = ::welder::naming::none>
552 static void add_field(auto& ut) {
553 constexpr const char* name{
555 constexpr bool read_only{std::meta::is_const_type(std::meta::type_of(Mem)) ||
557 if constexpr (!std::meta::is_public(Mem)) {
558 // A protected member (admitted under policy::weld_protected) binds
559 // as a sol::property over welder::detail::field_access — gcc-16
560 // rejects the dependent `&[:Mem:]` for protected data (see
561 // field_access).
563 if constexpr (read_only)
564 ut[name] = ::sol::readonly_property(&fa::get);
565 else
566 ut[name] = ::sol::property(&fa::get, &fa::set);
567 } else if constexpr (read_only) {
568 ut[name] = ::sol::readonly(&[:Mem:]);
569 } else {
570 ut[name] = &[:Mem:];
571 }
572 }
573
583 template <class T, std::meta::info Getter, std::meta::info Setter>
584 static void add_property(auto& ut, const char* name) {
586 if constexpr (Setter == std::meta::info{}) {
587 ut[name] = ::sol::readonly_property(&[:Getter:]);
588 } else if constexpr (std::is_void_v<
589 typename [:std::meta::return_type_of(Setter):]>) {
590 ut[name] = ::sol::property(&[:Getter:], &[:Setter:]);
591 } else {
592 // A value-returning setter (a fluent T& set_x(…)): discard the
593 // return — the property protocol has no slot for it, and the gate
594 // deliberately never checked it.
595 using Arg = typename
596 [:std::meta::type_of(std::meta::parameters_of(Setter)[0]):];
597 static constexpr auto sp{&[:Setter:]};
598 ut[name] = ::sol::property(
599 &[:Getter:],
600 [](T& self, Arg v) { (self.*sp)(std::forward<Arg>(v)); });
601 }
602 }
603
607 template <auto Fns, class Style = ::welder::naming::none>
608 static void add_method(auto& ut) {
610 ut,
612 std::make_index_sequence<Fns.size()>{});
613 }
614
617 template <auto Fns, class Style = ::welder::naming::none>
618 static void add_static_method(auto& ut) {
620 ut,
621 ::welder::name_of<Fns[0], language, Style,
623 std::make_index_sequence<Fns.size()>{});
624 }
625
634 template <class T, auto Fns>
635 static void add_operator(auto& ut) {
636 _register_operator<Fns>(ut, std::make_index_sequence<Fns.size()>{});
637 }
638
646 template <class T, auto Fns, auto Covered>
647 static void add_comparisons(auto& ut) {
648 constexpr auto seq{std::make_index_sequence<Fns.size()>{}};
649 if constexpr (!Covered[0])
651 if constexpr (!Covered[1])
653 }
654
658 template <class T, std::meta::info Fn>
659 static void add_stringifier(auto& ut) {
660 ut[::sol::meta_function::to_string] = &::welder::detail::stringify<T, Fn>;
661 }
662
663 private:
668 template <class T, auto Fns, ::welder::detail::cmp_slot S, class Target,
669 std::size_t... I>
670 static void _register_synth_cmp(Target& ut, std::index_sequence<I...>) {
671 constexpr ::sol::meta_function slot{
673 ? ::sol::meta_function::less_than
674 : ::sol::meta_function::less_than_or_equal_to};
676 ut[slot] = ::sol::overload(
677 &synthesized_comparison<
678 T,
679 std::remove_cvref_t<typename [: ::welder::detail::
680 comparison_operand(
681 Fns[I], ^^T) :]>,
682 S>::call...,
683 &synthesized_comparison<
684 std::remove_cvref_t<typename [: ::welder::detail::
685 comparison_operand(
686 Fns[I], ^^T) :]>,
687 T, S>::call...);
688 }
689
690 public:
691
692 // --- enum binding -------------------------------------------------------
693
696 template <class E>
697 static auto make_enum(module_type& m, const char* name, const char* /*doc*/) {
698 ::sol::table values{::sol::state_view{m.lua_state()}.create_table()};
699 m[name] = values;
700 return _enum_binding<E>{
701 values, [m](const char* n, lua_Integer v) mutable { m[n] = v; },
702 std::is_scoped_enum_v<E>};
703 }
704
710 template <class E>
711 static auto make_nested_enum(module_type& m, auto& outer, const char* name,
712 const char* /*doc*/) {
713 ::sol::table values{::sol::state_view{m.lua_state()}.create_table()};
714 outer[name] = values; // a reference value registers as a static entry
715 return _enum_binding<E>{
716 values,
717 // sol::var marks the plain integer as a STATIC variable — a bare
718 // value assignment would be wrapped as a bound function.
719 [outer](const char* n, lua_Integer v) mutable {
720 outer[n] = ::sol::var(v);
721 },
722 std::is_scoped_enum_v<E>};
723 }
724
730 template <std::meta::info Enum, class Style = ::welder::naming::none>
731 static void add_enumerator(auto& e) {
732 constexpr const char* name{
734 const lua_Integer value{static_cast<lua_Integer>(std::to_underlying([:Enum:]))};
735 e.values[name] = value;
736 if (!e.scoped)
737 e.mirror(name, value);
738 }
739
742 template <class /*E*/>
743 static void finish_enum(auto&) {}
744
745 // --- namespace / module binding -----------------------------------------
746
750 static session open_module(module_type&) { return {}; }
751
754 static void set_module_doc(module_type&, const char*) {}
755
763 template <auto Fns, class Style = ::welder::naming::none>
764 static sol::object add_function(module_type& m, const char* name = nullptr) {
765 const char* fn_name{::welder::name_of_or<
766 Fns[0], language, Style, ::welder::ent_kind::function>(name)};
767 _register_named<Fns>(m, fn_name, std::make_index_sequence<Fns.size()>{});
768 return m.get<sol::object>(fn_name);
769 }
770
783 template <std::meta::info Var, class Style = ::welder::naming::none>
784 static void add_variable(module_type& m, session& s, const char* name = nullptr) {
785 const char* key{::welder::name_of_or<Var, language, Style,
787 if constexpr (std::meta::is_const_type(std::meta::type_of(Var))) {
788 m[key] = [:Var:]; // immutable: a value snapshot at load time
789 } else {
790 if (!s.has_live) {
791 ::sol::state_view lua{m.lua_state()};
792 s.getters = lua.create_table();
793 s.setters = lua.create_table();
794 s.has_live = true;
795 }
796 s.getters[key] = [] { return [:Var:]; };
797 s.setters[key] = [](typename [:std::meta::type_of(Var):] v) {
798 [:Var:] = v;
799 };
800 }
801 }
802
804 static module_type add_submodule(module_type& m, const char* name) {
805 ::sol::table sub{::sol::state_view{m.lua_state()}.create_table()};
806 m[name] = sub;
807 return sub;
808 }
809
812 static void close_module(module_type& m, session& s) {
813 if (s.has_live)
815 }
816};
817
818static_assert(::welder::rod<rod>,
819 "welder::rods::sol2::rod must satisfy welder::rod");
820
821} // namespace welder::rods::sol2
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...
Definition concepts.hpp:263
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 aggregate_required_arity()
How many leading fields the synthesized aggregate field constructor REQUIRES: everything up to and in...
std::string stringify(const T &self)
The stringifier wrapper every runtime rod binds for a swept ostream inserter (see is_stringifier_for)...
cmp_slot
The rewritten-expression comparison a rod binds for a type whose C++ comparisons come from operator<=...
consteval metamethod operator_mm(std::meta::info f)
Map a member operator to its sol2 metamethod ({…, nullptr} = not exposed).
T(A...) ctor_sig
The alias T(A...) — a constructor call signature, built by substitute (a namespace-scope alias so it ...
Definition rod.hpp:90
consteval bool welded_for(std::meta::info type, lang L)
Is type welded for language L — i.e.
Definition reflect.hpp:40
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?
Definition reflect.hpp:243
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.
Definition lang.hpp:42
@ lua
Lua (via the sol2 and LuaBridge3 backends).
Definition lang.hpp:44
@ static_method
a static member function → transform_static_method.
Definition naming.hpp:325
@ function
a free function → transform_function.
Definition naming.hpp:326
@ variable
a namespace variable → transform_variable.
Definition naming.hpp:328
@ method
a member function → transform_method.
Definition naming.hpp:324
consteval void validate_return_policy()
Reject a return_policy on Fn (for language L) that contradicts Fn's return type.
Definition reflect.hpp:361
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...
Definition naming.hpp:424
consteval const char * name_of()
The final bound name of Ent (a K-kind entity) for language L under name style Style.
Definition naming.hpp:375
consteval std::vector< std::meta::info > public_bases(std::meta::info type)
The types of the public base classes of type.
Definition reflect.hpp:418
The C++-operator → sol2 metamethod map, factored out of the sol2 backend.
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.
Definition naming.hpp:259
::sol::meta_function fn
The sol2 metamethod slot.
const char * name
Its __name, or nullptr if not exposed.
A welded enum's binding: the name→value table, how to mirror a name onto the enclosing scope,...
Definition rod.hpp:164
std::function< void(const char *, lua_Integer)> mirror
Write one name onto the enclosing scope.
Definition rod.hpp:167
bool scoped
true for enum class.
Definition rod.hpp:168
::sol::table values
The E = { Name = value, … } table.
Definition rod.hpp:165
Per-module session: the deferred state for live namespace variables.
Definition rod.hpp:116
::sol::table getters
name → fun(): value (live reads).
Definition rod.hpp:117
bool has_live
any mutable variable registered?
Definition rod.hpp:119
::sol::table setters
name → fun(value) (live writes).
Definition rod.hpp:118
static void add_field(auto &ut)
Bind data member Mem as a usertype property.
Definition rod.hpp:552
static module_type add_submodule(module_type &m, const char *name)
Create a submodule table named name under m.
Definition rod.hpp:804
static consteval void _collect_welded_bases(std::meta::info type, lang L, std::vector< std::meta::info > &out)
Collect all welded ancestors of type (transitively), deduplicated.
Definition rod.hpp:309
static void set_module_doc(module_type &, const char *)
No runtime module docstring in Lua (its home is a generated stub).
Definition rod.hpp:754
::sol::usertype< T > class_handle_type
The class / enum handles the per-class / per-enum hooks operate on — exactly what make_class / make_e...
Definition rod.hpp:475
static auto make_class(module_type &m, const char *name, const char *, std::index_sequence< I... >)
Create the sol::usertype<T> handle (constructors are installed by the driver's subsequent add_constru...
Definition rod.hpp:502
static void _prev_newindex(const ::sol::object &prev, ::sol::table self, const ::sol::object &key, const ::sol::object &value)
Route a missing-key write on the module to a captured previous __newindex (function or table form); w...
Definition rod.hpp:408
static void add_static_method(auto &ut)
Bind static-method overload group Fns as a class-table function (T.name(…)), grouped as in add_method...
Definition rod.hpp:618
static void close_module(module_type &m, session &s)
Close the session: install the live-variable metatable proxy, if any mutable variable was welded onto...
Definition rod.hpp:812
static consteval const char * special_method_name(std::meta::info op_fn)
Map a member operator to its Lua metamethod name (nullptr = not exposed).
Definition rod.hpp:487
static void add_enumerator(auto &e)
Add enumerator Enum (as its underlying integer).
Definition rod.hpp:731
static auto make_nested_enum(module_type &m, auto &outer, const char *name, const char *)
Create the Name = value table for a nested member enum, placed on the enclosing type's usertype (modu...
Definition rod.hpp:711
static auto make_enum(module_type &m, const char *name, const char *)
Create the enum's Name = value table on the module (doc ignored).
Definition rod.hpp:697
static auto make_nested_class(module_type &m, auto &outer, const char *name, const char *doc, std::index_sequence< I... > seq)
Create the sol::usertype<T> for a nested member type, placed on the enclosing type's usertype table (...
Definition rod.hpp:520
static void _register_operator(Target &t, std::index_sequence< I... >)
Register operator group Grp under its Lua metamethod slot (a single callable, or a sol::overload(…) f...
Definition rod.hpp:382
_enum_binding< E > enum_handle_type
Definition rod.hpp:476
static void _install_live_variables(module_type &m, ::sol::table getters, ::sol::table setters)
Install (or extend) the module table's metatable so absent keys in getters / setters read and write t...
Definition rod.hpp:431
static void add_comparisons(auto &ut)
Synthesize __lt/__le from operator<=> group Fns via rewritten expressions (a < b, …) — Lua derives >,...
Definition rod.hpp:647
static sol::object add_function(module_type &m, const char *name=nullptr)
Bind free-function overload group Fns as one module-level function (a single callable,...
Definition rod.hpp:764
static consteval auto _ctor_sigs_array()
_ctor_signatures<T, …>() as a fixed-size, splice-ready static array.
Definition rod.hpp:226
static consteval std::vector< std::meta::info > _ctor_signatures()
The set of sol::constructors<…> signatures to expose for T, as function- type reflections T(A....
Definition rod.hpp:188
static consteval auto _welded_bases_array()
_collect_welded_bases for T as a fixed-size, splice-ready static array.
Definition rod.hpp:332
static void add_property(auto &ut, const char *name)
Bind the resolved property (Getter + optional Setter) as a usertype property named name (driver-resol...
Definition rod.hpp:584
static void finish_enum(auto &)
No whole-enum finalizer needed (unscoped export is done per-enumerator).
Definition rod.hpp:743
static void add_variable(module_type &m, session &s, const char *name=nullptr)
Bind namespace variable Var onto the module.
Definition rod.hpp:784
static void add_stringifier(auto &ut)
Bind the swept free ostream inserter Fn as __tostring (via welder::detail::stringify — print(obj) / t...
Definition rod.hpp:659
static void add_operator(auto &ut)
Bind operator slot group Fns under its Lua metamethod — one (operator, arity) slot whole,...
Definition rod.hpp:635
static void add_constructors(::sol::usertype< T > &ut)
Install T's whole constructor set — exactly what sol2 wants (one sol::constructors<…> assignment cove...
Definition rod.hpp:538
static void _set_constructors(::sol::usertype< T > &ut, std::index_sequence< I... >)
Register T's constructor set on the usertype from the reflected signatures.
Definition rod.hpp:247
static auto _make_usertype(::sol::table &m, const char *name, std::index_sequence< I... >)
Create m.new_usertype<T, Bases…>(name) with sol2's base-class linkage.
Definition rod.hpp:267
static session open_module(module_type &)
Open a per-module session.
Definition rod.hpp:750
static constexpr lang language
welder::lang::lua.
Definition rod.hpp:104
static constexpr bool has_native_caster
caster_oracle: T converts without welder registering a usertype iff sol2 does not classify it as need...
Definition rod.hpp:483
::sol::object _prev_index(::sol::this_state ts, const ::sol::object &prev, const ::sol::table &self, const ::sol::object &key)
Route a missing-key read on the module to a captured previous __index (function or table form),...
Definition rod.hpp:396
::sol::table module_type
A Lua module is a table.
Definition rod.hpp:105
static void _register_named(Target &t, const char *name, std::index_sequence< I... >)
Register overload group Grp on target t under the (already name-styled) name — a single callable when...
Definition rod.hpp:361
static void _register_synth_cmp(Target &ut, std::index_sequence< I... >)
Assign one synthesized comparison slot: a sol::overload of the rewritten-expression wrappers,...
Definition rod.hpp:670
static constexpr bool _needs_registration
Whether sol2 can only convert T via runtime usertype registration.
Definition rod.hpp:151
static void add_method(auto &ut)
Bind method overload group Fns as one method (obj:name(…)) — a single callable when unique,...
Definition rod.hpp:608
welder's binding entry point: the welder::welder struct.