welder 0.1.0
Bindings for annotated C++ types, from C++26 reflection
Loading...
Searching...
No Matches
bindable.hpp
Go to the documentation of this file.
1#pragma once
2#include <array>
3#include <concepts>
4#include <cstddef>
5#include <meta>
6#include <type_traits>
7#include <utility>
8
9// The STL templates named in the element-wise wrapper table below must be
10// complete/visible so `^^std::vector` & friends resolve.
11#include <deque>
12#include <list>
13#include <map>
14#include <memory>
15#include <optional>
16#include <set>
17#include <string>
18#include <tuple>
19#include <unordered_map>
20#include <unordered_set>
21#include <variant>
22#include <vector>
23
24#include <welder/bind_traits.hpp> // param_types (for signature asserts)
25#include <welder/concepts.hpp> // caster_oracle (the backend leaf test)
26#include <welder/reflect.hpp> // welded_for
27
46
47namespace welder::inline v0 {
48
61 static consteval bool counts_as_registered(std::meta::info type, lang L) {
62 return welder::welded_for(type, L);
63 }
64};
65
66namespace detail {
67
69template <caster_oracle B, class T, lang L, class Reg>
70consteval bool bindable();
71
90 std::meta::info tmpl;
91 std::size_t values;
92};
93
95consteval std::array<wrapper_spec, 18> stl_wrappers() {
96 return {{
97 {^^std::vector, 1}, {^^std::list, 1},
98 {^^std::deque, 1}, {^^std::set, 1},
99 {^^std::multiset, 1}, {^^std::unordered_set, 1},
100 {^^std::unordered_multiset, 1},
101 {^^std::map, 2}, {^^std::multimap, 2},
102 {^^std::unordered_map, 2}, {^^std::unordered_multimap, 2},
103 {^^std::optional, 1}, {^^std::shared_ptr, 1},
104 {^^std::unique_ptr, 1}, {^^std::pair, 2},
105 {^^std::array, 1}, {^^std::tuple, 0},
106 {^^std::variant, 0},
107 }};
108}
109
116consteval long wrapper_value_count(std::meta::info type) {
117 if (!std::meta::has_template_arguments(type))
118 return -1;
119 const std::meta::info tmpl{std::meta::template_of(type)};
120 for (const wrapper_spec& w : stl_wrappers())
121 if (w.tmpl == tmpl)
122 return w.values != 0 ? static_cast<long>(w.values)
123 : static_cast<long>(
124 std::meta::template_arguments_of(type).size());
125 return -1;
126}
127
132template <std::meta::info Type, std::size_t N>
133consteval std::array<std::meta::info, N> leading_args() {
134 std::array<std::meta::info, N> out{};
135 std::size_t i{0};
136 for (auto arg : std::meta::template_arguments_of(Type)) {
137 if (i == N)
138 break;
139 out[i++] = arg;
140 }
141 return out;
142}
143
151template <caster_oracle B, lang L, class Reg, auto Args, std::size_t... I>
152consteval bool args_bindable(std::index_sequence<I...>) {
153 return (bindable<B, typename [:Args[I]:], L, Reg>() && ...);
154}
155
168template <caster_oracle B, class T, lang L, class Reg>
169consteval bool bindable() {
170 // Strip cv/ref/pointer so the STL-wrapper table below sees the bare
171 // specialization (a parameter may arrive as `const std::vector<Foo>&`).
172 // dealias because remove_* are alias templates: their reflection is an alias
173 // carrying neither template arguments nor annotations — the underlying type
174 // does. remove_cvref handles the ref+cv combo, then remove_pointer, then a
175 // final remove_cv for a pointee's constness (`const Foo*` -> `Foo`).
176 constexpr std::meta::info u{std::meta::dealias(
177 ^^std::remove_cv_t<std::remove_pointer_t<std::remove_cvref_t<T>>>)};
179 // Type-level escape hatch: the user vouches this type is registered /
180 // convertible outside welder's view. Checked first, and on every recursion
181 // level, so trusting `Foo` also clears `Foo*`, `const Foo&` and
182 // `std::vector<Foo>` (whose element recurses back to a trusted `Foo`).
183 return true;
184 } else {
185 constexpr long values{wrapper_value_count(u)};
186 if constexpr (values >= 0) {
187 constexpr auto args{leading_args<u, static_cast<std::size_t>(values)>()};
189 std::make_index_sequence<args.size()>{});
190 } else if constexpr (B::template has_native_caster<typename [:u:]>) {
191 return true;
192 } else {
193 return Reg::counts_as_registered(u, L);
194 }
195 }
196}
197
198} // namespace detail
199
209template <caster_oracle B, class T, lang L, class Reg = welded_registration>
210consteval bool bindable() {
212}
213
223template <caster_oracle B, class T, lang L, class Reg = welded_registration>
224consteval void assert_bindable() {
225 static_assert(
227 "welder: cannot bind this C++ type to the target language. Weld it with "
228 "[[=welder::weld(...)]], or register a backend type converter for it; "
229 "otherwise mark::exclude the member that uses it. The offending type is "
230 "the template argument of this assert_bindable<B, T, L> instantiation.");
231}
232
233namespace detail {
234
241template <caster_oracle B, std::meta::info Fn, lang L, class Reg, std::size_t... I>
242consteval void assert_params_bindable(std::index_sequence<I...>) {
243 static constexpr auto params{param_types<Fn>()};
245}
246
247} // namespace detail
248
257template <caster_oracle B, std::meta::info Fn, lang L,
258 class Reg = welded_registration>
260 // Guard n != 0: param_types<Fn> materializes a std::array<info, n>, and
261 // std::array<info, 0>::operator[] is not consteval (it must not be
262 // instantiated for a parameterless function).
263 constexpr std::size_t n{std::meta::parameters_of(Fn).size()};
264 if constexpr (n != 0)
265 detail::assert_params_bindable<B, Fn, L, Reg>(std::make_index_sequence<n>{});
266 if constexpr (!std::meta::is_constructor(Fn)) {
267 using R = [:std::meta::return_type_of(Fn):];
268 if constexpr (!std::is_void_v<R>)
270 }
271}
272
273// --- member-aware asserts (honor the trust_bindable member mark) -------------
274//
275// The driver uses these at each emission site: they run the bindability gate on a
276// member's type / a callable's signature *unless* the member carries a
277// [[=welder::mark::trust_bindable]] mark for L, in which case the user has vouched
278// for the type and the gate is skipped. (The type-level trust_bindable<T> point is
279// folded into bindable() itself, above, so it needs no per-site handling.)
280
286template <caster_oracle B, std::meta::info Member, lang L,
287 class Reg = welded_registration>
288consteval void assert_member_bindable() {
289 if constexpr (!welder::trusted_for(Member, L))
290 assert_bindable<B, typename [:std::meta::type_of(Member):], L, Reg>();
291}
292
298template <caster_oracle B, std::meta::info Fn, lang L,
299 class Reg = welded_registration>
300consteval void assert_callable_bindable() {
301 if constexpr (!welder::trusted_for(Fn, L))
303}
304
305} // namespace welder
Backend-agnostic selection layer: the reflection predicates and selectors that decide what participat...
The core interface concepts welder's static polymorphism rests on, gathered in one catalogue: the cus...
The one bindability fact a backend must provide: can it natively convert a type without welder regist...
Definition concepts.hpp:86
consteval std::array< wrapper_spec, 18 > stl_wrappers()
The element-wise STL-wrapper table welder recurses into.
Definition bindable.hpp:95
consteval void assert_params_bindable(std::index_sequence< I... >)
Assert every parameter type of Fn binds.
Definition bindable.hpp:242
consteval bool args_bindable(std::index_sequence< I... >)
Whether every one of a wrapper's value arguments (spliced back to types) binds.
Definition bindable.hpp:152
consteval auto param_types()
A function's parameter types, as a static array of reflections.
consteval long wrapper_value_count(std::meta::info type)
How many leading arguments of type to recurse if it is a listed wrapper.
Definition bindable.hpp:116
consteval bool bindable()
Forward declaration: bindable() recurses through a container's element types.
Definition bindable.hpp:169
consteval std::array< std::meta::info, N > leading_args()
The first N template arguments of Type, as a splice-ready static array.
Definition bindable.hpp:133
consteval bool welded_for(std::meta::info type, lang L)
Is type welded for language L — i.e.
Definition reflect.hpp:26
consteval void assert_callable_bindable()
Assert a function/method/operator/constructor signature binds, unless trusted.
Definition bindable.hpp:300
consteval void assert_bindable()
Hard error the instant welder would bind an unbindable type.
Definition bindable.hpp:224
consteval bool bindable()
Is T bindable to language L under backend B?
Definition bindable.hpp:210
consteval bool trusted_for(std::meta::info member, lang L)
Does member carry a trust_bindable mark covering language L?
Definition reflect.hpp:208
lang
The target languages welder ships rods for — but not the whole value space.
Definition lang.hpp:42
consteval void assert_member_bindable()
Assert the type of a data member / namespace variable binds, unless trusted.
Definition bindable.hpp:288
consteval void assert_signature_bindable()
Assert every parameter type and the (non-void) return type of Fn binds.
Definition bindable.hpp:259
constexpr bool trust_bindable
The type-level trust customization point: specialize to true to trust T wherever it appears (member,...
Language-agnostic resolution: given a reflected type/member and a target language,...
One row of the element-wise STL-wrapper table.
Definition bindable.hpp:89
std::size_t values
Leading arguments to recurse; 0 = all.
Definition bindable.hpp:91
std::meta::info tmpl
The class template, e.g.
Definition bindable.hpp:90
The default registration oracle of the bindability gate: a program-defined class/enum type counts as ...
Definition bindable.hpp:59
static consteval bool counts_as_registered(std::meta::info type, lang L)
Does welding under this policy provide a registration for type?
Definition bindable.hpp:61