#ifndef CUTES_MIRROR_H #define CUTES_MIRROR_H #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) #endif // !CUTES_MIRROR_H