2024-01-26 21:58:02 +00:00
|
|
|
#ifndef CUTES_MIRROR_H
|
|
|
|
#define CUTES_MIRROR_H
|
2024-01-25 13:08:23 +00:00
|
|
|
|
|
|
|
#include "typeclass_helpers.h"
|
|
|
|
#include "stdint.h"
|
|
|
|
#include "string.h"
|
|
|
|
#include "dictionary.h"
|
|
|
|
#include "strutil.h" // included because the impl macros require strhash
|
|
|
|
|
|
|
|
typedef uintptr_t typeid;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
const char* (*const get_typestring)(void* self);
|
|
|
|
typeid (*const get_typeid)(void* self);
|
|
|
|
Dictionary* (*const get_typeclasses)(void* self);
|
|
|
|
} IMirror;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
void* data;
|
|
|
|
union {
|
|
|
|
IMirror const* tc;
|
|
|
|
// this is cursed, but it allows the TC_CAST macro to work
|
|
|
|
IMirror const* mirror;
|
|
|
|
};
|
|
|
|
} Mirror;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
const void* typeclass;
|
|
|
|
void* function;
|
|
|
|
} MirroredTypeclass;
|
|
|
|
|
|
|
|
static inline int mirror_is_typeid(const Mirror* mirror, typeid id) {
|
|
|
|
return mirror->tc->get_typeid(mirror->data) == id;
|
|
|
|
}
|
|
|
|
static inline int mirror_is_typestring(const Mirror* mirror, const char* id) {
|
|
|
|
return strcmp(id, mirror->tc->get_typestring(mirror->data)) == 0;
|
|
|
|
}
|
|
|
|
static inline int mirror_eq(const Mirror* lhs, const Mirror* rhs) {
|
|
|
|
return lhs->tc->get_typeid(lhs->data) == rhs->tc->get_typeid(rhs->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern const void* mirror_get_typeclass(void* data, IMirror const* tc, const char* typeclass);
|
|
|
|
// get the wrapper function for a given typeclass name
|
|
|
|
// example:
|
|
|
|
// mirror_get_function(physics_entity.data, physics_entity.mirror, "BehaviourEntity")
|
|
|
|
extern void* mirror_get_function(void* data, IMirror const* tc, const char* typeclass_name);
|
|
|
|
|
|
|
|
// macro reexport of mirror_get_function which will cast the function so it can be called immediately
|
|
|
|
// example:
|
|
|
|
// MIRROR_GET_WRAP_FUNC(physics_entity.data, physics_entity.mirror, BehaviourEntity)(physics_entity.data)
|
|
|
|
#define MIRROR_GET_WRAP_FUNC(Data_, MirrorTc_, Typeclass_)\
|
|
|
|
((Typeclass_(*)(void*))mirror_get_function(Data_, MirrorTc_, #Typeclass_))
|
|
|
|
|
|
|
|
// casting only works if the typeclass in question exposes IMirror as .mirror
|
|
|
|
// will segfault if the Mirror does not expose To_
|
|
|
|
// example:
|
|
|
|
// TC_CAST(physics_entity, BehaviourEntity)
|
|
|
|
#define TC_CAST(From_, To_)\
|
|
|
|
MIRROR_GET_WRAP_FUNC(From_.data, From_.mirror, To_)(From_.data)
|
|
|
|
|
|
|
|
#define TC_MIRRORS(From_, To_)\
|
|
|
|
MIRROR_GET_WRAP_FUNC(From_.data, From_.mirror, To_) != NULL
|
|
|
|
|
|
|
|
#define MIRROR_TRY_WRAP(Into_, Mirror_, Typeclass_){\
|
|
|
|
MirroredTypeclassWrapFunc fn_ = mirror_get_typeclass(Mirror_, #Typeclass_);\
|
|
|
|
if(fn_ != NULL) {\
|
|
|
|
Into_ = (TypeClass_)fn(Mirror_->data);\
|
|
|
|
}\
|
|
|
|
}
|
|
|
|
|
|
|
|
#define impl_Mirror_for(T, get_typestring_f, get_typeid_f, get_typeclasses_f)\
|
|
|
|
Mirror T##_as_Mirror(T* x) {\
|
|
|
|
TC_FN_TYPECHECK(const char*, get_typestring_f, T*);\
|
|
|
|
TC_FN_TYPECHECK(typeid, get_typeid_f, T*);\
|
|
|
|
TC_FN_TYPECHECK(Dictionary*, get_typeclasses_f, T*);\
|
|
|
|
static IMirror const tc = {\
|
|
|
|
.get_typestring = (const char*(*const)(void*)) get_typestring_f,\
|
|
|
|
.get_typeid = (typeid (*const)(void*)) get_typeid_f,\
|
|
|
|
.get_typeclasses = (Dictionary* (*const)(void*)) get_typeclasses_f,\
|
|
|
|
};\
|
|
|
|
return (Mirror){.tc = &tc, .data = x};\
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DECL_REFLECT(T)\
|
|
|
|
extern const char* T##_get_typestring(T* self);\
|
|
|
|
extern typeid T##_get_typeid(T* self);\
|
|
|
|
extern Dictionary* T##_get_typeclasses(T* self);\
|
|
|
|
decl_typeclass_impl(Mirror, T)
|
|
|
|
|
|
|
|
#define START_REFLECT(T)\
|
|
|
|
const char* T##_get_typestring(T* self) {\
|
|
|
|
static const char* const typestring = #T;\
|
|
|
|
return typestring;\
|
|
|
|
}\
|
|
|
|
typeid T##_get_typeid(T* self) {\
|
|
|
|
static char init_flag = 0;\
|
|
|
|
static typeid id = 0;\
|
|
|
|
if(!init_flag) {\
|
|
|
|
init_flag = 1;\
|
|
|
|
id = strhash(#T);\
|
|
|
|
}\
|
|
|
|
return id;\
|
|
|
|
}\
|
|
|
|
Dictionary* T##_get_typeclasses(T* self) {\
|
|
|
|
static char init_flag = 0;\
|
|
|
|
static Dictionary typeclasses;\
|
|
|
|
if(!init_flag) {\
|
|
|
|
init_flag = 1;\
|
|
|
|
typeclasses = dictionary_new(sizeof(MirroredTypeclass));\
|
|
|
|
MirroredTypeclass tc;\
|
|
|
|
REFLECT_TYPECLASS(T, Mirror)
|
|
|
|
|
|
|
|
#define REFLECT_TYPECLASS(T, TypeClass_)\
|
|
|
|
tc = (MirroredTypeclass){\
|
|
|
|
.typeclass = (void*)T##_as_##TypeClass_(NULL).tc,\
|
|
|
|
.function = (void*)T##_as_##TypeClass_\
|
|
|
|
};\
|
|
|
|
dictionary_set_raw(&typeclasses, #TypeClass_, &tc);
|
|
|
|
|
|
|
|
#define END_REFLECT(T)\
|
|
|
|
}\
|
|
|
|
return &typeclasses;\
|
|
|
|
}\
|
|
|
|
impl_Mirror_for(T, T##_get_typestring, T##_get_typeid, T##_get_typeclasses)
|
|
|
|
|
2024-01-26 21:58:02 +00:00
|
|
|
#endif // !CUTES_MIRROR_H
|