// // typecast.h // reflection // // Created by Sam Jaffe on 7/4/22. // Copyright © 2022 Sam Jaffe. All rights reserved. // #pragma once #include #include #include #include #if defined __has_include #if __has_include() #include #endif #endif #include "reflection/forward.h" #include "reflection/object.h" namespace reflection { template class TypeCast { public: static bool has_cast(Object const & obj) { return get_.count(obj.type()); } static T get(Object const & obj) { return get_.at(obj.type())(obj); } static void set(Object & obj, T const & value) { set_.at(obj.type())(obj, value); } operator bool() const { return true; } template TypeCast & bind(T (*to)(I), O (*from)(S)) { bind_impl(to, from); TypeCast>().template bind_impl(from, to); return *this; } template TypeCast & bind() { #if defined NEARGYE_MAGIC_ENUM_HPP if constexpr (std::is_same_v && std::is_enum_v) { bind([](V const &str) -> T { return *magic_enum::enum_cast(str); }, [](T val) { return std::string(magic_enum::enum_name(val)); }); } else #endif if constexpr (!std::is_same_v) { bind_impl(); TypeCast().template bind_impl(); } return *this; } template TypeCast & bind() { return bind().template bind(); } private: template void bind_impl(T (*to)(I), O (*from)(S)) { static_assert(std::is_same_v, T>, "this types must be compatible"); static_assert(std::is_same_v, std::decay_t>, "cast types must be compatible"); using V = std::decay_t; get_.emplace(typeid(V), [to](auto & obj) { return to(static_cast(obj)); }); set_.emplace(typeid(V), [from](auto & obj, T const & val) { static_cast(obj) = from(val); }); } template void bind_impl() { get_.emplace(typeid(V), [](auto & obj) { return static_cast(static_cast(obj)); }); set_.emplace(typeid(V), [](auto & obj, T val) { static_cast(obj) = static_cast(val); }); } private: template friend class TypeCast; static TypeMap> get_; static TypeMap> set_; }; template TypeMap> TypeCast::get_; template TypeMap> TypeCast::set_; } #if defined REFLECTION_TYPE_CAST_IMPLEMENTATION namespace reflection { INSTANTIATE_REFLECTION_TYPECAST(bool); INSTANTIATE_REFLECTION_TYPECAST(int16_t); INSTANTIATE_REFLECTION_TYPECAST(int32_t); INSTANTIATE_REFLECTION_TYPECAST(int64_t); INSTANTIATE_REFLECTION_TYPECAST(uint16_t); INSTANTIATE_REFLECTION_TYPECAST(uint32_t); INSTANTIATE_REFLECTION_TYPECAST(uint64_t); INSTANTIATE_REFLECTION_TYPECAST(float); INSTANTIATE_REFLECTION_TYPECAST(double); INSTANTIATE_REFLECTION_TYPECAST(long double); INSTANTIATE_REFLECTION_TYPECAST(std::string, "string"); // Bind boolean types to all integer types REFLECTION_TYPE_CAST(bool) .bind() .bind(); // Bind all integer types (wider than 1byte) to each other. REFLECTION_TYPE_CAST(int32_t) .bind() .bind() .bind(); REFLECTION_TYPE_CAST(uint32_t) .bind() .bind() .bind(); REFLECTION_TYPE_CAST(int16_t) .bind() .bind() .bind(); REFLECTION_TYPE_CAST(uint16_t) .bind() .bind() .bind(); REFLECTION_TYPE_CAST(int64_t) .bind() .bind() .bind(); REFLECTION_TYPE_CAST(uint64_t) .bind() .bind() .bind(); // Mututally bind all floating point numbers REFLECTION_TYPE_CAST(float).bind(); REFLECTION_TYPE_CAST(double).bind(); REFLECTION_TYPE_CAST(long double).bind(); } #endif