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
73#include <array>
74#include <cstddef>
75#include <meta>
76#include <string>
77#include <type_traits>
78#include <utility>
79#include <vector>
80
81#include <welder/welder.hpp> // welder::welder + rod contract + driver
82#include <welder/rods/lua/metamethods.hpp> // shared operator -> Lua __name map
83#include <welder/bind_traits.hpp> // aggregate_* helpers
84
85// LuaBridge3 requires the Lua headers to be visible first (its Config.h hard-errors
86// otherwise). Pull them in here so a binding TU only needs this rod header, the way
87// the sol2 rod gets Lua transitively through <sol/sol.hpp>. lua.hpp is the C++
88// convenience wrapper every PUC-Lua / LuaJIT distribution ships.
89#include <lua.hpp>
90
91#include <LuaBridge/LuaBridge.h>
92
93// Make every C++ enum convert to/from a Lua integer. By default LuaBridge3 treats
94// an unspecialized type as userdata, so an enum-typed function parameter/return
95// would demand a registered userdata; welder instead binds an enum as a table of
96// integer values (see make_enum), so its values cross the boundary as integers.
97// This blanket specialization — the generalization of LuaBridge3's opt-in
98// `Stack<E> = Enum<E>` — makes that work for any welded enum without per-enum glue.
99namespace luabridge {
100template <class E>
101struct Stack<E, std::enable_if_t<std::is_enum_v<E>>> : Enum<E> {};
102} // namespace luabridge
103
104namespace welder::inline v0::rods::luabridge {
105
106// The welder rod namespace `welder::rods::luabridge` would shadow the library's
107// `::luabridge`, so alias it (as the Python rods alias pybind11/nanobind) and use
108// `lb::` throughout.
109namespace lb = ::luabridge;
110
112
116template <class... A>
117using ctor_sig = void(A...);
118
124template <class T, class... A>
125T make_object(A... args) {
126 return T(std::move(args)...);
127}
128
139struct rod {
140 static constexpr lang language{lang::lua};
141
150 lua_State* L{nullptr};
151 std::vector<std::string> path{};
152 };
154
159 struct session {};
160
164 template <class T>
166 using type = T;
168 std::string name;
169 };
170
179 struct enum_handle {
181 std::string name;
182 bool scoped;
183 std::string outer_key{};
184 };
185
190 template <class T> using class_handle_type = class_handle<T>;
191 template <class> using enum_handle_type = enum_handle;
192
193 protected:
194 // --- implementation helpers (not part of the welder::rod contract) --
195
210 template <class T>
211 static constexpr bool _needs_registration =
212 std::is_enum_v<std::remove_cvref_t<T>> ||
213 lb::detail::IsUserdata<std::remove_cvref_t<T>>::value;
214
216 template <class H>
217 using _class_type = typename std::remove_cvref_t<H>::type;
218
224 static lb::Namespace _open_namespace(const module_scope& m) {
225 lb::Namespace ns{lb::getGlobalNamespace(m.L)};
226 for (const auto& seg : m.path)
227 ns = ns.beginNamespace(seg.c_str());
228 return ns;
229 }
230
236 template <class T>
237 static auto _open_class(const module_scope& m, const char* name) {
238 return _open_namespace(m).template beginClass<T>(name);
239 }
240
249 static void _push_module_table(const module_scope& m) {
250 lua_pushglobaltable(m.L);
251 for (const auto& seg : m.path) {
252 lua_pushlstring(m.L, seg.data(), seg.size());
253 lua_rawget(m.L, -2);
254 lua_remove(m.L, -2);
255 }
256 }
257
263 template <class T, auto Ctors, bool HasDefault, bool Aggregate>
264 static consteval std::vector<std::vector<std::meta::info>> _ctor_arg_lists() {
265 std::vector<std::vector<std::meta::info>> lists;
266 if (HasDefault)
267 lists.push_back({}); // ()
268 for (auto c : Ctors) {
269 std::vector<std::meta::info> args;
270 for (auto p : std::meta::parameters_of(c))
271 args.push_back(std::meta::type_of(p));
272 lists.push_back(args);
273 }
274 // constexpr-if: the branch indexes the field array, which must not be
275 // instantiated for a fieldless type (the array<info, 0> trap) — and
276 // Aggregate guarantees at least one field.
277 if constexpr (Aggregate) {
278 // One arity per omissible NSDMI-suffix tail (aggregate_required_arity):
279 // C++26 parenthesized aggregate init fills omitted trailing fields
280 // from their NSDMIs, so T(prefix…) is valid for every prefix length
281 // down to the required arity. Arity 0 would duplicate the default
282 // constructor's signature, so it starts at 1 when that is bound.
285 if (HasDefault && start == 0)
286 start = 1;
287 for (std::size_t arity{start}; arity <= fields.size(); ++arity) {
288 std::vector<std::meta::info> args;
289 for (std::size_t i{0}; i < arity; ++i)
290 args.push_back(std::meta::type_of(fields[i]));
291 lists.push_back(args);
292 }
293 }
294 return lists;
295 }
296
299 template <class T, auto Ctors, bool HasDefault, bool Aggregate>
300 static consteval auto _ctor_sigs_array() {
301 constexpr std::size_t n{
303 std::array<std::meta::info, n> out{};
304 if constexpr (n != 0) {
306 for (std::size_t i{0}; i < n; ++i)
307 out[i] = std::meta::dealias(std::meta::substitute(^^ctor_sig, lists[i]));
308 }
309 return out;
310 }
311
314 template <class T, auto Ctors, bool HasDefault, bool Aggregate>
315 static consteval auto _factory_array() {
316 constexpr std::size_t n{
318 std::array<std::meta::info, n> out{};
319 if constexpr (n != 0) {
321 for (std::size_t i{0}; i < n; ++i) {
322 std::vector<std::meta::info> targs{^^T};
323 for (auto a : lists[i])
324 targs.push_back(a);
325 out[i] = std::meta::substitute(^^make_object, targs);
326 }
327 }
328 return out;
329 }
330
335 template <auto Sigs, auto Factories, class Cls, std::size_t... I>
336 static void _add_constructors(Cls& cls, std::index_sequence<I...>) {
337 cls.template addConstructor<typename [:Sigs[I]:]...>();
338 cls.addStaticFunction("new", &[:Factories[I]:]...);
339 }
340
345 template <class T, auto Bases, std::size_t... I>
346 static void _make_class(const module_scope& m, const char* name,
347 std::index_sequence<I...>) {
348 if constexpr (sizeof...(I) == 0) {
349 auto cls{_open_namespace(m).template beginClass<T>(name)};
350 } else {
351 auto cls{_open_namespace(m)
352 .template deriveClass<T, typename [:Bases[I]:]...>(name)};
353 }
354 }
355
361 template <auto Grp, class Target, std::size_t... I>
362 static void _add_function(Target& t, const char* name,
363 std::index_sequence<I...>) {
364 // LuaBridge3 owns a returned object structurally (a value → a Lua-owned
365 // copy; a pointer/reference → a non-owning view), so a
366 // [[=welder::return_policy]] has no runtime effect here — but a
367 // self-contradictory one (a reference to a returned temporary) is still
368 // rejected, uniformly with the Python rods.
370 t.addFunction(name, &[:Grp[I]:]...);
371 }
372
374 template <auto Grp, class Target, std::size_t... I>
375 static void _add_static_function(Target& t, const char* name,
376 std::index_sequence<I...>) {
378 t.addStaticFunction(name, &[:Grp[I]:]...);
379 }
380
381 public:
382 // --- caster oracle + emission primitives (the welder::rod contract) --
383
388 template <class T>
390
393 static consteval const char* special_method_name(std::meta::info op_fn) {
394 return lua_metamethod_name(op_fn);
395 }
396
397 // --- class binding ------------------------------------------------------
398
403 template <class T, auto Bases, std::size_t... I>
404 static class_handle<T> make_class(module_type& m, const char* name,
405 const char* /*doc*/,
406 std::index_sequence<I...> /*seq*/) {
407 _make_class<T, Bases>(m, name, std::make_index_sequence<Bases.size()>{});
408 return class_handle<T>{m, std::string{name}};
409 }
410
420 template <class T, auto Bases, std::size_t... I>
422 const char* name, const char* /*doc*/,
423 std::index_sequence<I...> /*seq*/) {
424 std::string temp{outer.name + "." + name};
425 _make_class<T, Bases>(outer.mod, temp.c_str(),
426 std::make_index_sequence<Bases.size()>{});
427 return class_handle<T>{outer.mod, std::move(temp)};
428 }
429
437 template <class T>
438 static void finish_nested_class(module_type&, auto& outer, auto& cls,
439 const char* name) {
440 lua_State* L{cls.mod.L};
441 _push_module_table(cls.mod); // [mod]
442 lua_pushlstring(L, cls.name.data(), cls.name.size());
443 lua_rawget(L, -2); // [mod, inner]
444 lua_pushlstring(L, outer.name.data(), outer.name.size());
445 lua_rawget(L, -3); // [mod, inner, outerT]
446 lua_pushstring(L, name);
447 lua_pushvalue(L, -3); // [.., outerT, name, inner]
448 lua_rawset(L, -3); // outerT[name] = inner
449 lua_pop(L, 2); // [mod]
450 lua_pushlstring(L, cls.name.data(), cls.name.size());
451 lua_pushnil(L);
452 lua_rawset(L, -3); // mod["Outer.Inner"] = nil
453 lua_pop(L, 1);
454 }
455
463 template <class T, auto Ctors, bool HasDefault, bool Aggregate, bool Copyable,
464 class Style = ::welder::naming::none>
465 static void add_constructors(auto& h) {
467 constexpr auto factories{_factory_array<T, Ctors, HasDefault, Aggregate>()};
468 if constexpr (sigs.size() != 0) {
469 auto cls{_open_class<T>(h.mod, h.name.c_str())};
471 cls, std::make_index_sequence<sigs.size()>{});
472 }
473 }
474
485 template <std::meta::info Mem, class Style = ::welder::naming::none>
486 static void add_field(auto& h) {
487 using T = _class_type<decltype(h)>;
488 constexpr const char* name{
490 constexpr bool read_only{std::meta::is_const_type(std::meta::type_of(Mem)) ||
492 auto cls{_open_class<T>(h.mod, h.name.c_str())};
493 if constexpr (!std::meta::is_public(Mem)) {
494 // A protected member (admitted under policy::weld_protected) binds
495 // as a getter/setter property over welder::detail::field_access —
496 // gcc-16 rejects the dependent `&[:Mem:]` for protected data (see
497 // field_access).
499 if constexpr (read_only)
500 cls.addProperty(name, &fa::get);
501 else
502 cls.addProperty(name, &fa::get, &fa::set);
503 } else {
504 using Field = typename [:std::meta::type_of(Mem):];
505 constexpr Field T::* mp{&[:Mem:]};
506 if constexpr (read_only)
507 cls.addProperty(name, mp); // read-only (const or no_reassign)
508 else
509 cls.addProperty(name, mp, mp); // read/write
510 }
511 }
512
526 template <class T, std::meta::info Getter, std::meta::info Setter>
527 static void add_property(auto& h, const char* name) {
529 auto cls{_open_class<T>(h.mod, h.name.c_str())};
530 using GF = typename [:std::meta::type_of(Getter):];
531 static constexpr GF T::* get{&[:Getter:]};
532 if constexpr (Setter == std::meta::info{}) {
533 cls.addProperty(name, get);
534 } else {
535 using SF = typename [:std::meta::type_of(Setter):];
536 static constexpr SF T::* set{&[:Setter:]};
537 if constexpr (std::meta::dealias(std::meta::return_type_of(Setter)) ==
538 ^^void) {
539 cls.addProperty(name, get, set);
540 } else {
541 // A value-returning setter: wrap both halves as callables and
542 // discard the setter's return (the property protocol has no
543 // slot for it).
544 using Arg = typename
545 [:std::meta::type_of(std::meta::parameters_of(Setter)[0]):];
546 cls.addProperty(
547 name, [](const T* self) -> decltype(auto) { return (self->*get)(); },
548 [](T* self, Arg v) { (self->*set)(std::forward<Arg>(v)); });
549 }
550 }
551 }
552
556 template <auto Fns, class Style = ::welder::naming::none>
557 static void add_method(auto& h) {
558 using T = _class_type<decltype(h)>;
559 auto cls{_open_class<T>(h.mod, h.name.c_str())};
561 cls,
563 std::make_index_sequence<Fns.size()>{});
564 }
565
568 template <auto Fns, class Style = ::welder::naming::none>
569 static void add_static_method(auto& h) {
570 using T = _class_type<decltype(h)>;
571 auto cls{_open_class<T>(h.mod, h.name.c_str())};
573 cls,
574 ::welder::name_of<Fns[0], language, Style,
576 std::make_index_sequence<Fns.size()>{});
577 }
578
605 template <class T, auto Fns>
606 static void add_operator(auto& h) {
607 constexpr auto Fn{Fns[0]};
608 {
609 auto cls{_open_class<T>(h.mod, h.name.c_str())};
610 if constexpr (std::meta::operator_of(Fn) ==
611 std::meta::operators::op_square_brackets) {
612 using Key = std::remove_cvref_t<typename [:std::meta::type_of(
613 std::meta::parameters_of(Fn)[0]):]>;
614 cls.addIndexMetaMethod(
615 +[](T& self, const lb::LuaRef& key, lua_State* L) -> lb::LuaRef {
616 if constexpr (std::is_arithmetic_v<Key>) {
617 key.push(L); // may be a stringified number (see above)
618 int is_num{0};
619 const lua_Number n{lua_tonumberx(L, -1, &is_num)};
620 lua_pop(L, 1);
621 if (!is_num)
622 return lb::LuaRef(L); // not a subscript key
623 return lb::LuaRef(L, self[static_cast<Key>(n)]);
624 } else {
625 if (auto k = key.template cast<Key>())
626 return lb::LuaRef(L, self[*k]);
627 return lb::LuaRef(L); // nil: fall through to member lookup
628 }
629 });
630 } else {
631 constexpr const char* slot{lua_metamethod_name(Fn)};
632 constexpr auto direct{
635 cls, slot, std::make_index_sequence<direct.size()>{});
636 }
637 }
638 }
639
646 template <class T, auto Fns, auto Covered>
647 static void add_comparisons(auto& h) {
648 auto cls{_open_class<T>(h.mod, h.name.c_str())};
649 constexpr auto seq{std::make_index_sequence<Fns.size()>{}};
650 if constexpr (!Covered[0])
652 seq);
653 if constexpr (!Covered[1])
655 seq);
656 }
657
660 template <class T, std::meta::info Fn>
661 static void add_stringifier(auto& h) {
662 auto cls{_open_class<T>(h.mod, h.name.c_str())};
663 cls.addFunction("__tostring", &::welder::detail::stringify<T, Fn>);
664 }
665
666 private:
676 template <class T, auto Fns, auto Direct, class C, std::size_t... I>
677 static void _add_operator_slot(C& cls, const char* slot,
678 std::index_sequence<I...>) {
679 template for (constexpr auto fn : std::define_static_array(Fns)) {
681 }
682 if constexpr (Direct.size() == Fns.size())
683 cls.addFunction(slot, &[:Direct[I]:]...);
684 else
685 cls.addFunction(slot, &_op_dispatch<T, Fns>);
686 }
687
691 template <class T, auto Fns>
692 static int _op_dispatch(lua_State* L) {
693 int done{-1};
694 template for (constexpr auto fn : std::define_static_array(Fns)) {
695 if (done < 0)
697 }
698 if (done < 0)
699 return luaL_error(
700 L, "welder: no matching operator overload for these operands");
701 return done;
702 }
703
708 template <class T, std::meta::info Fn>
709 static int _try_operator_entry(lua_State* L) {
710 if (lua_gettop(L) < 2)
711 return -1;
712 const lb::LuaRef a{lb::LuaRef::fromStack(L, 1)};
713 const lb::LuaRef b{lb::LuaRef::fromStack(L, 2)};
714 if constexpr (std::meta::is_class_member(Fn)) {
715 using B_ = std::remove_cvref_t<typename [:std::meta::type_of(
716 std::meta::parameters_of(Fn)[0]):]>;
717 const auto vb{b.template cast<B_>()};
718 if (!vb)
719 return -1;
720 if constexpr (requires(const T& s, const B_& x) { s.[:Fn:](x); }) {
721 const auto pt{a.template cast<const T*>()};
722 if (!pt || *pt == nullptr)
723 return -1;
724 return _push_result(L, ((**pt).[:Fn:])(*vb));
725 } else {
726 const auto pt{a.template cast<T*>()};
727 if (!pt || *pt == nullptr)
728 return -1;
729 return _push_result(L, ((**pt).[:Fn:])(*vb));
730 }
731 } else {
732 using A_ = std::remove_cvref_t<typename [:std::meta::type_of(
733 std::meta::parameters_of(Fn)[0]):]>;
734 using B_ = std::remove_cvref_t<typename [:std::meta::type_of(
735 std::meta::parameters_of(Fn)[1]):]>;
736 const auto va{a.template cast<A_>()};
737 if (!va)
738 return -1;
739 const auto vb{b.template cast<B_>()};
740 if (!vb)
741 return -1;
742 return _push_result(L, [:Fn:](*va, *vb));
743 }
744 }
745
747 template <class R>
748 static int _push_result(lua_State* L, R&& v) {
749 const auto r{lb::Stack<std::remove_cvref_t<R>>::push(
750 L, std::forward<R>(v))};
751 if (!r)
752 return luaL_error(L, "welder: failed to push operator result");
753 return 1;
754 }
755
762 template <class T, auto Fns, ::welder::detail::cmp_slot S, class C,
763 std::size_t... I>
764 static void _add_synth_cmp(C& cls, const char* name,
765 std::index_sequence<I...>) {
768 ^^T>())
769 cls.addFunction(name, &_cmp_dispatch<T, Fns, S>);
770 else
771 cls.addFunction(
772 name,
773 &synthesized_comparison<
774 T,
775 std::remove_cvref_t<typename [: ::welder::detail::
776 comparison_operand(
777 Fns[I], ^^T) :]>,
778 S>::call...);
779 }
780
783 template <class T, auto Fns, ::welder::detail::cmp_slot S>
784 static int _cmp_dispatch(lua_State* L) {
785 int done{-1};
786 template for (constexpr auto fn : std::define_static_array(Fns)) {
787 using P = std::remove_cvref_t<
788 typename [: ::welder::detail::comparison_operand(fn, ^^T) :]>;
789 if (done < 0)
790 done = _try_cmp<T, P, S, false>(L);
791 if constexpr (!std::is_same_v<P, T>) {
792 if (done < 0)
793 done = _try_cmp<T, P, S, true>(L);
794 }
795 }
796 if (done < 0)
797 return luaL_error(
798 L, "welder: no matching comparison for these operands");
799 return done;
800 }
801
804 template <class T, class P, ::welder::detail::cmp_slot S, bool Rev>
805 static int _try_cmp(lua_State* L) {
806 using A_ = std::conditional_t<Rev, P, T>;
807 using B_ = std::conditional_t<Rev, T, P>;
808 if (lua_gettop(L) < 2)
809 return -1;
810 const auto va{lb::LuaRef::fromStack(L, 1).template cast<A_>()};
811 if (!va)
812 return -1;
813 const auto vb{lb::LuaRef::fromStack(L, 2).template cast<B_>()};
814 if (!vb)
815 return -1;
816 return _push_result(
818 *vb));
819 }
820
821 public:
822 // --- enum binding -------------------------------------------------------
823
826 template <class E>
827 static enum_handle make_enum(module_type& m, const char* name,
828 const char* /*doc*/) {
829 _open_namespace(m).beginNamespace(name); // create (empty), then unwind
830 return enum_handle{m, std::string{name}, std::is_scoped_enum_v<E>};
831 }
832
839 template <class E>
841 const char* name, const char* /*doc*/) {
842 lua_State* L{outer.mod.L};
843 _push_module_table(outer.mod); // [mod]
844 lua_pushlstring(L, outer.name.data(), outer.name.size());
845 lua_rawget(L, -2); // [mod, outerT]
846 lua_pushstring(L, name);
847 lua_newtable(L); // [.., name, values]
848 lua_rawset(L, -3); // outerT[name] = {}
849 lua_pop(L, 2);
850 return enum_handle{outer.mod, std::string{name}, std::is_scoped_enum_v<E>,
851 outer.name};
852 }
853
859 template <std::meta::info Enum, class Style = ::welder::naming::none>
860 static void add_enumerator(enum_handle& e) {
861 constexpr const char* name{
863 const lua_Integer value{static_cast<lua_Integer>(std::to_underlying([:Enum:]))};
864 if (e.outer_key.empty()) {
865 _open_namespace(e.mod).beginNamespace(e.name.c_str()).addVariable(name, value);
866 if (!e.scoped)
867 _open_namespace(e.mod).addVariable(name, value);
868 } else {
869 // Class-nested: write through the outer's table with raw ops (the
870 // value table is a raw static entry created by make_nested_enum).
871 lua_State* L{e.mod.L};
872 _push_module_table(e.mod); // [mod]
873 lua_pushlstring(L, e.outer_key.data(), e.outer_key.size());
874 lua_rawget(L, -2); // [mod, outerT]
875 lua_pushlstring(L, e.name.data(), e.name.size());
876 lua_rawget(L, -2); // [mod, outerT, values]
877 lua_pushstring(L, name);
878 lua_pushinteger(L, value);
879 lua_rawset(L, -3); // values[name] = v
880 lua_pop(L, 1); // [mod, outerT]
881 if (!e.scoped) {
882 lua_pushstring(L, name);
883 lua_pushinteger(L, value);
884 lua_rawset(L, -3); // outerT[name] = v
885 }
886 lua_pop(L, 2);
887 }
888 }
889
892 template <class /*E*/>
893 static void finish_enum(auto&) {}
894
895 // --- namespace / module binding -----------------------------------------
896
898 static session open_module(module_type&) { return {}; }
899
902 static void set_module_doc(module_type&, const char*) {}
903
908 template <auto Fns, class Style = ::welder::naming::none>
909 static void add_function(module_type& m, const char* name = nullptr) {
910 lb::Namespace ns{_open_namespace(m)};
912 ns,
913 ::welder::name_of_or<Fns[0], language, Style,
915 std::make_index_sequence<Fns.size()>{});
916 }
917
925 template <std::meta::info Var, class Style = ::welder::naming::none>
926 static void add_variable(module_type& m, session& /*s*/,
927 const char* name = nullptr) {
928 const char* key{::welder::name_of_or<Var, language, Style,
930 lb::Namespace ns{_open_namespace(m)};
931 if constexpr (std::meta::is_const_type(std::meta::type_of(Var))) {
932 ns.addVariable(key, [:Var:]); // immutable: a value snapshot at load time
933 } else {
934 using VT = typename [:std::meta::type_of(Var):];
935 ns.addProperty(
936 key, +[]() -> VT { return [:Var:]; }, +[](VT v) { [:Var:] = v; });
937 }
938 }
939
941 static module_type add_submodule(module_type& m, const char* name) {
942 _open_namespace(m).beginNamespace(name); // create, then unwind
943 module_type sub{m};
944 sub.path.emplace_back(name);
945 return sub;
946 }
947
950};
951
952static_assert(::welder::rod<rod>,
953 "welder::rods::luabridge::rod must satisfy welder::rod");
954
955} // namespace welder::rods::luabridge
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 C++-operator → Lua metamethod name map, shared by both Lua runtime rods (sol2 and LuaBridge3).
The stored forms of the annotation vocabulary.
consteval auto partition_reflected()
Split slot group Fns by free_operator_reflected — the entries whose reflectedness equals Reflected,...
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...
consteval std::meta::info comparison_operand(std::meta::info f, std::meta::info type)
The operand a comparison synthesized from spaceship overload f takes: the parameter type that is not ...
consteval bool has_heterogeneous_comparison()
Whether spaceship group Fns contains a heterogeneous overload (an operand that is not Type itself) — ...
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 const char * lua_metamethod_name(std::meta::info f)
Map an operator (member or anchored free) to its Lua metamethod __name, or nullptr if welder does not...
T make_object(A... args)
A factory that constructs T from the constructor arguments (works for normal constructors and,...
Definition rod.hpp:125
consteval const char * lua_metamethod_name(std::meta::info f)
Map an operator (member or anchored free) to its Lua metamethod __name, or nullptr if welder does not...
void(A...) ctor_sig
The alias void(A...) — a LuaBridge3 constructor signature (a function type whose parameters are the c...
Definition rod.hpp:117
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
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
Splice-based accessors for data member Mem — the pointer-to-member-free route the rods bind a protect...
static bool call(const A &a, const B &b)
Evaluate a OP b through C++'s rewriting rules.
The identity style: bind every C++ identifier unchanged.
Definition naming.hpp:259
The class handle threaded from make_class to the add_* hooks: enough to re-open the class (its module...
Definition rod.hpp:165
std::string name
The class's Lua name.
Definition rod.hpp:168
module_scope mod
The enclosing module.
Definition rod.hpp:167
The enum handle threaded from make_enum to add_enumerator: the enclosing module, the enum's Lua name ...
Definition rod.hpp:179
A copyable handle to a welded module (or submodule) table: the borrowed Lua state plus the namespace ...
Definition rod.hpp:149
lua_State * L
The borrowed Lua state.
Definition rod.hpp:150
std::vector< std::string > path
Namespace segments under _G.
Definition rod.hpp:151
Per-module session — unused: LuaBridge3 registers namespace variables as live properties eagerly (no ...
Definition rod.hpp:159
static void _make_class(const module_scope &m, const char *name, std::index_sequence< I... >)
Create the class registration with its native (welded nearest-ancestor) bases, in one chained express...
Definition rod.hpp:346
static consteval auto _factory_array()
The make_object<T, A...> factory-function reflections (for the .new static function) as a fixed-size,...
Definition rod.hpp:315
static void _add_static_function(Target &t, const char *name, std::index_sequence< I... >)
As _add_function, for a class's static methods (addStaticFunction).
Definition rod.hpp:375
static int _push_result(lua_State *L, R &&v)
Push an operator result and report success to Lua.
Definition rod.hpp:748
static constexpr lang language
welder::lang::lua.
Definition rod.hpp:140
static void add_operator(auto &h)
Bind operator slot group Fns under its Lua metamethod __name — one (operator, arity) slot whole,...
Definition rod.hpp:606
static module_type add_submodule(module_type &m, const char *name)
Create a submodule (nested namespace) named name under m.
Definition rod.hpp:941
static enum_handle make_enum(module_type &m, const char *name, const char *)
Create the enum's nested namespace (a Name = value table) on the module (doc ignored) and return a re...
Definition rod.hpp:827
static consteval auto _ctor_sigs_array()
The void(A...) constructor-signature reflections (for addConstructor) as a fixed-size,...
Definition rod.hpp:300
static int _try_cmp(lua_State *L)
Try one comparison direction: stack = (T, P), or (P, T) when Rev.
Definition rod.hpp:805
static void add_field(auto &h)
Bind data member Mem as a class property (read-only if const or marked [[=welder::mark::no_reassign]]...
Definition rod.hpp:486
module_scope module_type
A Lua module is a named table.
Definition rod.hpp:153
static constexpr bool _needs_registration
Whether LuaBridge3 can only convert T via runtime class registration.
Definition rod.hpp:211
static class_handle< T > make_nested_class(module_type &, auto &outer, const char *name, const char *, std::index_sequence< I... >)
Register a nested member type T under a temporary dotted module key ("Outer.Inner").
Definition rod.hpp:421
static void _add_synth_cmp(C &cls, const char *name, std::index_sequence< I... >)
Register one synthesized comparison slot.
Definition rod.hpp:764
static enum_handle make_nested_enum(module_type &, auto &outer, const char *name, const char *)
Create the Name = value table for a nested member enum directly inside the enclosing class's table (m...
Definition rod.hpp:840
static consteval std::vector< std::vector< std::meta::info > > _ctor_arg_lists()
The set of constructor argument lists to expose for T, built from the pieces the DRIVER hands to add_...
Definition rod.hpp:264
enum_handle enum_handle_type
Definition rod.hpp:191
static void _push_module_table(const module_scope &m)
Push the module's namespace table onto the Lua stack (a raw walk from _G through the path segments); ...
Definition rod.hpp:249
typename std::remove_cvref_t< H >::type _class_type
The C++ type behind a class_handle<T>& (deduced from the driver's auto&).
Definition rod.hpp:217
static void add_static_method(auto &h)
Bind static-method overload group Fns as a class-table function (T.name(…)), grouped as in add_method...
Definition rod.hpp:569
static void add_function(module_type &m, const char *name=nullptr)
Bind free-function overload group Fns as one module-level function (a single variadic addFunction; na...
Definition rod.hpp:909
static void add_variable(module_type &m, session &, const char *name=nullptr)
Bind namespace variable Var onto the module.
Definition rod.hpp:926
static class_handle< T > make_class(module_type &m, const char *name, const char *, std::index_sequence< I... >)
Register class T (with its native bases and constructors) and return a re-openable handle.
Definition rod.hpp:404
static void _add_constructors(Cls &cls, std::index_sequence< I... >)
Register the whole constructor set on the (live) class cls: both the call form T(…) (addConstructor,...
Definition rod.hpp:336
static void add_method(auto &h)
Bind method overload group Fns as one method (obj:name(…)) via a single variadic addFunction — LuaBri...
Definition rod.hpp:557
static void add_stringifier(auto &h)
Bind the swept free ostream inserter Fn as __tostring (via welder::detail::stringify).
Definition rod.hpp:661
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:393
static void add_comparisons(auto &h)
Synthesize __lt/__le from operator<=> group Fns via rewritten expressions — Lua derives >,...
Definition rod.hpp:647
static void add_constructors(auto &h)
Register T's whole constructor set — exactly what LuaBridge3 wants (one variadic addConstructor for t...
Definition rod.hpp:465
static void _add_function(Target &t, const char *name, std::index_sequence< I... >)
Register overload group Grp on target t (a live class or namespace) under name via LuaBridge3's varia...
Definition rod.hpp:362
static void close_module(module_type &, session &)
Close the session (no-op; see session).
Definition rod.hpp:949
static void add_property(auto &h, const char *name)
Bind the resolved property (Getter + optional Setter) as a class property named name (driver-resolved...
Definition rod.hpp:527
static void finish_enum(auto &)
No whole-enum finalizer needed (unscoped export is done per-enumerator).
Definition rod.hpp:893
static constexpr bool has_native_caster
caster_oracle: T converts without welder registering a class iff LuaBridge3 does not classify it as n...
Definition rod.hpp:389
static void finish_nested_class(module_type &, auto &outer, auto &cls, const char *name)
Move the fully-registered nested class table onto the outer's class table (module....
Definition rod.hpp:438
static int _cmp_dispatch(lua_State *L)
The raw comparison dispatcher: per spaceship overload, try the forward (T, P) order,...
Definition rod.hpp:784
class_handle< T > class_handle_type
The class / enum handles the per-class / per-enum hooks receive — exactly what make_class / make_enum...
Definition rod.hpp:190
static int _try_operator_entry(lua_State *L)
Try one (binary) entry: convert both operands to the entry's declared types — by value via LuaRef::ca...
Definition rod.hpp:709
static lb::Namespace _open_namespace(const module_scope &m)
Open the module's namespace chain from the global namespace, returning the innermost luabridge::Names...
Definition rod.hpp:224
static auto _open_class(const module_scope &m, const char *name)
Re-open class T under name in module m, returning the live luabridge::Namespace::Class<T> (created by...
Definition rod.hpp:237
static void set_module_doc(module_type &, const char *)
No runtime module docstring in Lua (its home is a generated stub).
Definition rod.hpp:902
static session open_module(module_type &)
Open a per-module session (unused; see session).
Definition rod.hpp:898
static void add_enumerator(enum_handle &e)
Add enumerator Enum (as its underlying integer) to the enum's table.
Definition rod.hpp:860
static int _op_dispatch(lua_State *L)
The raw slot dispatcher: try each entry in turn against the operands on the stack (Lua hands a metame...
Definition rod.hpp:692
static void _add_operator_slot(C &cls, const char *slot, std::index_sequence< I... >)
Register one operator slot.
Definition rod.hpp:677
welder's binding entry point: the welder::welder struct.