16#include <nlohmann/json.hpp>
21#include <toast/events/signal_types.hpp>
39enum class FieldType : uint8_t {
53 using SignalGetterPtr = std::vector<signals::ConnectionInfo> (*)(
void*);
54 using SignalConnectPtr = void (*)(
void*,
Node&, std::string_view, signals::ConnectionSource, bool);
55 using SignalDisconnectPtr = void (*)(
void*,
Node&, std::string_view, signals::ConnectionSource);
56 using SignalClearPtr = void (*)(
void*, signals::ConnectionSource);
57 using SignalFirePtr = bool (*)(
void*, std::span<const std::any>);
59 std::string_view name;
60 std::string_view type;
61 std::vector<const std::type_info*> args;
62 nlohmann::json attributes;
65 SignalConnectPtr connect;
66 SignalDisconnectPtr disconnect;
80 using FieldGetterPtr = std::any (*)(
void*);
81 using FieldSetterPtr = void (*)(
void*, std::any);
83 std::string_view name;
84 std::string_view type;
86 nlohmann::json attributes;
87 bool is_array =
false;
97 if (attributes.is_object()) {
100 if (attributes.is_array() && attributes.size() == 1 && attributes.front().is_object()) {
101 return &attributes.front();
120 return map !=
nullptr && map->contains(std::string(attr_name));
131 if (map ==
nullptr) {
134 auto it = map->find(std::string(attr_name));
135 if (it == map->end() || !it->is_array() || it->empty()) {
138 return it->at(0).get<std::string>();
146 std::string_view name;
147 std::string_view type;
148 std::optional<std::string_view> default_value;
149 const std::type_info* type_id;
164 std::string_view name;
165 std::string_view return_type;
166 const std::type_info* return_type_id;
167 std::span<const ParameterInfo> parameters;
168 nlohmann::json attributes;
173 auto attributeMap() const -> const nlohmann::json* {
174 if (attributes.is_object()) {
177 if (attributes.is_array() && attributes.size() == 1 && attributes.front().is_object()) {
178 return &attributes.front();
184 auto hasAttribute(std::string_view attr_name)
const ->
bool {
185 const auto* map = attributeMap();
186 return map !=
nullptr && map->contains(std::string(attr_name));
190 auto getAttribute(std::string_view attr_name)
const -> std::string {
191 const auto* map = attributeMap();
192 if (map ==
nullptr) {
195 auto it = map->find(std::string(attr_name));
196 if (it == map->end() || !it->is_array() || it->empty()) {
199 return it->at(0).get<std::string>();
202 template<
typename R = void,
typename... Args>
203 auto call(
void* obj, Args&&... args)
const -> R {
205 parameters.size() ==
sizeof...(Args) && return_type_id !=
nullptr && *return_type_id ==
typeid(std::decay_t<R>);
207 const std::array<
const std::type_info*,
sizeof...(Args)> expected = {&
typeid(std::decay_t<Args>)...};
208 for (std::size_t i = 0; i < expected.size(); ++i) {
209 if (parameters[i].type_id ==
nullptr || *parameters[i].type_id != *expected[i]) {
210 signature_ok =
false;
216 TOAST_WARN(
"Reflect",
"call(): signature mismatch for '{}'; invoking is undefined behavior", name);
217 assert(
false &&
"FunctionInfo::call(): argument or return type mismatch");
220 using Trampoline = R (*)(
void*, std::decay_t<Args>...);
221 auto* trampoline =
reinterpret_cast<Trampoline
>(invoke);
222 return trampoline(obj, std::forward<Args>(args)...);
234 auto callDynamic(
void* obj, std::span<const std::any> args)
const -> std::any {
235 if (!invoke_dynamic) {
236 TOAST_WARN(
"Reflect",
"callDynamic(): no dynamic invoker for '{}' (was it compiled with an older generator?)", name);
239 return invoke_dynamic(obj, args);
256template<
typename Tag>
258 inline static typename Tag::type member;
261template<
typename Tag,
typename Tag::type Ptr>
263 Robber() { Accessor<Tag>::member = Ptr; }
265 static Robber instance;
268template<
typename Tag,
typename Tag::type Ptr>
283template<
class Class,
typename FieldType,
typename Tag>
285 static auto get(
void* obj) -> std::any {
return static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member; }
287 static void set(
void* obj, std::any value) {
288 if (
auto* typed = std::any_cast<FieldType>(&value)) {
289 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member = *typed;
294 if constexpr (std::is_integral_v<FieldType>) {
295 const auto& type_info = value.type();
296 if (type_info ==
typeid(
int)) {
297 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
static_cast<FieldType
>(std::any_cast<int>(value));
298 }
else if (type_info ==
typeid(
unsigned int)) {
299 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
300 static_cast<FieldType
>(std::any_cast<unsigned int>(value));
301 }
else if (type_info ==
typeid(
long)) {
302 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
static_cast<FieldType
>(std::any_cast<long>(value));
303 }
else if (type_info ==
typeid(
unsigned long)) {
304 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
305 static_cast<FieldType
>(std::any_cast<unsigned long>(value));
306 }
else if (type_info ==
typeid(
short)) {
307 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
static_cast<FieldType
>(std::any_cast<short>(value));
308 }
else if (type_info ==
typeid(
unsigned short)) {
309 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
310 static_cast<FieldType
>(std::any_cast<unsigned short>(value));
311 }
else if (type_info ==
typeid(
char)) {
312 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
static_cast<FieldType
>(std::any_cast<char>(value));
313 }
else if (type_info ==
typeid(
unsigned char)) {
314 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
315 static_cast<FieldType
>(std::any_cast<unsigned char>(value));
324template<
class Class,
typename FieldType,
typename Tag>
326 static auto get(
void* obj) -> std::any {
327 if constexpr (std::is_enum_v<FieldType>) {
328 using Underlying = std::underlying_type_t<FieldType>;
329 const Underlying value =
static_cast<Underlying
>(
static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member);
330 if constexpr (std::is_signed_v<Underlying>) {
331 return std::any {
static_cast<int64_t
>(value)};
333 return std::any {
static_cast<uint64_t
>(value)};
336 return FieldAccess<Class, FieldType, Tag>::get(obj);
340 static void set(
void* obj, std::any value) {
341 if constexpr (std::is_enum_v<FieldType>) {
342 auto assign = [obj](
auto numeric) {
343 using Underlying = std::underlying_type_t<FieldType>;
344 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member =
345 static_cast<FieldType
>(
static_cast<Underlying
>(numeric));
348 if (
const auto* v = std::any_cast<int>(&value)) {
350 }
else if (
const auto* v = std::any_cast<unsigned int>(&value)) {
352 }
else if (
const auto* v = std::any_cast<int64_t>(&value)) {
354 }
else if (
const auto* v = std::any_cast<uint64_t>(&value)) {
356 }
else if (
const auto* v = std::any_cast<long>(&value)) {
358 }
else if (
const auto* v = std::any_cast<unsigned long>(&value)) {
360 }
else if (
const auto* v = std::any_cast<short>(&value)) {
362 }
else if (
const auto* v = std::any_cast<unsigned short>(&value)) {
364 }
else if (
const auto* v = std::any_cast<char>(&value)) {
366 }
else if (
const auto* v = std::any_cast<unsigned char>(&value)) {
370 FieldAccess<Class, FieldType, Tag>::set(obj, std::move(value));
381template<
class Class,
typename T,
typename Tag>
383 static auto get(
void* obj) -> std::any {
384 Box<T>& src =
static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member;
388 static void set(
void* obj, std::any value) {
389 if (
auto* box = std::any_cast<
Box<Node>>(&value)) {
390 static_cast<Class*
>(obj)->*_detail::template Accessor<Tag>::member = box->as<T>();
pseudo shared pointer for Nodes
Intrusive reference-counted handle to a Node.
Definition box.hpp:35
Definition reflect.hpp:244
Public logging interface for the engine.
#define TOAST_WARN(sink,...)
Indicates possible code missuse.
Definition log.hpp:94
Member-robber pattern used by the generated reflection code.
Definition defer.hpp:16
Field accessor that exchanges enum values through their int representation.
Definition reflect.hpp:325
Generated getter/setter pair binding a private member pointer to the FieldInfo interface.
Definition reflect.hpp:284
Runtime descriptor for one reflected field.
Definition reflect.hpp:79
auto getAttribute(std::string_view attr_name) const -> std::string
Returns the first string value of a JSON annotation.
Definition reflect.hpp:129
auto groupName() const -> std::string
Returns the value of the "Group" annotation, or an empty string if not present.
Definition reflect.hpp:108
auto hasAttribute(std::string_view attr_name) const -> bool
Checks whether a JSON annotation key is present on this field.
Definition reflect.hpp:118
auto attributeMap() const -> const nlohmann::json *
Returns the generated attribute objectpr.
Definition reflect.hpp:96
Runtime descriptor for one reflected member function.
Definition reflect.hpp:157
std::any(*)(void *obj, std::span< const std::any > args) DynamicInvoker
receives args as std::any, returns std::any (void → empty std::any)
Definition reflect.hpp:162
auto callDynamic(void *obj, std::span< const std::any > args) const -> std::any
Calls the function with runtime-typed arguments for scripting dispatch.
Definition reflect.hpp:234
void(*)() Invoker
Generic erased trampoline pointer; reinterpret_cast back to the real signature before calling.
Definition reflect.hpp:159
Runtime descriptor for one parameter of a reflected function.
Definition reflect.hpp:145
Definition reflect.hpp:52
Definition reflect.hpp:257
Definition reflect.hpp:262
Unique identifier for everything that exists in our engine.