Bladeren bron

refactor: dont have multiple bind() for functions in TypeCast
refactor: undef REFLECTION helpers
fix: add int <-> float conversions
feat: add magic_enum binding rule with __has_include
feat: add proxy with member and setter (which is a weird use-case tbh)

Sam Jaffe 3 jaren geleden
bovenliggende
commit
215f43c3b4
3 gewijzigde bestanden met toevoegingen van 43 en 12 verwijderingen
  1. 4 0
      include/reflection/proxy.h
  2. 14 0
      include/reflection/reflection.h
  3. 25 12
      include/reflection/typecast.h

+ 4 - 0
include/reflection/proxy.h

@@ -18,6 +18,10 @@ public:
   template <typename O>
   Proxy(O & obj, T (O::*get)() const, void (O::*set)(T))
       : data_((obj.*get)()), set_([&obj, set](auto & v) { (obj.*set)(v); }) {}
+  
+  template <typename O>
+  Proxy(O & obj, T O::*member, void (O::*set)(T))
+      : data_(obj.*member), set_([&obj, set](auto & v) { (obj.*set)(v); }) {}
 
   ~Proxy() { set_(data_); }
 

+ 14 - 0
include/reflection/reflection.h

@@ -10,6 +10,8 @@
 #include "reflection/object.h"
 #include "reflection/proxy.h"
 
+#define BIND_F(expr) [](auto &_) -> decltype(auto) { return expr; }
+
 #define REFLECTION_F(expr)                                                     \
   [=](Obj & obj, std::string name) { return Object(expr, std::move(name)); }
 #define CONST_REFLECTION_F(expr)                                               \
@@ -50,6 +52,15 @@ public:
     const_members_.emplace(id, CONST_REFLECTION_F((obj.*get)()));
     return *this;
   }
+  
+  template <typename R, typename I>
+  Reflection & bind(std::string_view id, R Obj::*member,
+                    void (Obj::*set)(I)) {
+    using V = std::decay_t<R>;
+    members_.emplace(id, REFLECTION_F(Proxy<V>(obj, member, set)));
+    const_members_.emplace(id, CONST_REFLECTION_F(obj.*member));
+    return *this;
+  }
 
   template <typename R>
   Reflection & bind(std::string_view id, R (Obj::*get)() const,
@@ -117,3 +128,6 @@ Cache<Accessor<Obj>> Reflection<Obj, Void>::members_;
 template <typename Obj, typename Void>
 Cache<Getter<Obj>> Reflection<Obj, Void>::const_members_;
 }
+
+#undef REFLECTION_F
+#undef CONST_REFLECTION_F

+ 25 - 12
include/reflection/typecast.h

@@ -13,6 +13,12 @@
 #include <unordered_map>
 #include <utility>
 
+#if defined __has_include
+#if __has_include(<magic_enum.hpp>)
+#include <magic_enum.hpp>
+#endif
+#endif
+
 #include "reflection/forward.h"
 #include "reflection/object.h"
 
@@ -31,17 +37,18 @@ public:
 
   template <typename I, typename O, typename S>
   TypeCast & bind(T (*to)(I), O (*from)(S)) {
-    return bind(std::function(to), std::function(from));
-  }
-
-  template <typename I, typename O, typename S>
-  TypeCast & bind(std::function<T(I)> to, std::function<O(S)> from) {
     bind_impl(to, from);
     TypeCast<std::decay_t<I>>().template bind_impl(from, to);
     return *this;
   }
 
   template <typename V> TypeCast & bind() {
+#if defined NEARGYE_MAGIC_ENUM_HPP
+    if constexpr (std::is_same_v<V, std::string> && std::is_enum_v<T>) {
+      bind<V const &, V, T>([](V const &str) -> T { return *magic_enum::enum_cast<T>(str); },
+                            [](T val) { return std::string(magic_enum::enum_name(val)); });
+    } else
+#endif
     if constexpr (!std::is_same_v<V, T>) {
       bind_impl<V>();
       TypeCast<V>().template bind_impl<T>();
@@ -55,7 +62,7 @@ public:
 
 private:
   template <typename I, typename O, typename S>
-  void bind_impl(std::function<T(I)> to, std::function<O(S)> from) {
+  void bind_impl(T (*to)(I), O (*from)(S)) {
     static_assert(std::is_same_v<std::decay_t<S>, T>,
                   "this types must be compatible");
     static_assert(std::is_same_v<std::decay_t<I>, std::decay_t<I>>,
@@ -111,27 +118,33 @@ REFLECTION_TYPE_CAST(bool)
 // Bind all integer types (wider than 1byte) to each other.
 REFLECTION_TYPE_CAST(int32_t)
     .bind<int16_t, int32_t, int64_t>()
-    .bind<uint16_t, uint32_t, uint64_t>();
+    .bind<uint16_t, uint32_t, uint64_t>()
+    .bind<float, double, long double>();
 
 REFLECTION_TYPE_CAST(uint32_t)
     .bind<int16_t, int32_t, int64_t>()
-    .bind<uint16_t, uint32_t, uint64_t>();
+    .bind<uint16_t, uint32_t, uint64_t>()
+    .bind<float, double, long double>();
 
 REFLECTION_TYPE_CAST(int16_t)
     .bind<int16_t, int32_t, int64_t>()
-    .bind<uint16_t, uint32_t, uint64_t>();
+    .bind<uint16_t, uint32_t, uint64_t>()
+    .bind<float, double, long double>();
 
 REFLECTION_TYPE_CAST(uint16_t)
     .bind<int16_t, int32_t, int64_t>()
-    .bind<uint16_t, uint32_t, uint64_t>();
+    .bind<uint16_t, uint32_t, uint64_t>()
+    .bind<float, double, long double>();
 
 REFLECTION_TYPE_CAST(int64_t)
     .bind<int16_t, int32_t, int64_t>()
-    .bind<uint16_t, uint32_t, uint64_t>();
+    .bind<uint16_t, uint32_t, uint64_t>()
+    .bind<float, double, long double>();
 
 REFLECTION_TYPE_CAST(uint64_t)
     .bind<int16_t, int32_t, int64_t>()
-    .bind<uint16_t, uint32_t, uint64_t>();
+    .bind<uint16_t, uint32_t, uint64_t>()
+    .bind<float, double, long double>();
 
 // Mututally bind all floating point numbers
 REFLECTION_TYPE_CAST(float).bind<float, double, long double>();