diff --git a/src/rttr/detail/property/property_wrapper.h b/src/rttr/detail/property/property_wrapper.h index 7089c729..f7a5ed1c 100644 --- a/src/rttr/detail/property/property_wrapper.h +++ b/src/rttr/detail/property/property_wrapper.h @@ -61,6 +61,7 @@ class property_wrapper; #include "rttr/detail/property/property_wrapper_member_func.h" #include "rttr/detail/property/property_wrapper_func.h" +#include "rttr/detail/property/property_wrapper_member_functor.h" #include "rttr/detail/property/property_wrapper_member_object.h" #include "rttr/detail/property/property_wrapper_object.h" diff --git a/src/rttr/detail/property/property_wrapper_func.h b/src/rttr/detail/property/property_wrapper_func.h index 76d7758c..e63dac11 100644 --- a/src/rttr/detail/property/property_wrapper_func.h +++ b/src/rttr/detail/property/property_wrapper_func.h @@ -32,8 +32,8 @@ ///////////////////////////////////////////////////////////////////////////////////////// // global function getter/setter - function pointer -template -class property_wrapper +template +class property_wrapper : public property_wrapper_base, public metadata_handler { using return_type = typename function_traits::return_type; @@ -43,7 +43,7 @@ class property_wrapper metadata_list) RTTR_NOEXCEPT - : property_wrapper_base(name, type::get()), + : property_wrapper_base(name, type::get()), metadata_handler(std::move(metadata_list)), m_getter(get), m_setter(set) { @@ -79,7 +79,7 @@ class property_wrapper(prop, m_getter, m_setter); + auto obj = make_property_getter_setter_info(prop, m_getter, m_setter); visitor_iterator::visit(visitor, make_property_getter_setter_visitor_invoker(obj)); } @@ -92,8 +92,8 @@ class property_wrapper -class property_wrapper +template +class property_wrapper : public property_wrapper_base, public metadata_handler { using return_type = typename function_traits::return_type; @@ -101,7 +101,7 @@ class property_wrapper metadata_list) RTTR_NOEXCEPT - : property_wrapper_base(name, type::get()), + : property_wrapper_base(name, type::get()), metadata_handler(std::move(metadata_list)), m_accessor(get) { @@ -131,7 +131,7 @@ class property_wrapper(prop, m_accessor); + auto obj = make_property_info(prop, m_accessor); visitor_iterator::visit(visitor, make_property_visitor_invoker(obj)); } @@ -145,8 +145,8 @@ class property_wrapper -class property_wrapper +template +class property_wrapper : public property_wrapper_base, public metadata_handler { using return_type = typename function_traits::return_type; @@ -156,7 +156,7 @@ class property_wrapper metadata_list) RTTR_NOEXCEPT - : property_wrapper_base(name, type::get()), + : property_wrapper_base(name, type::get()), metadata_handler(std::move(metadata_list)), m_getter(get), m_setter(set) { @@ -197,7 +197,7 @@ class property_wrapper(prop, m_getter, m_setter); + auto obj = make_property_getter_setter_info(prop, m_getter, m_setter); visitor_iterator::visit(visitor, make_property_getter_setter_visitor_invoker(obj)); } @@ -210,15 +210,15 @@ class property_wrapper -class property_wrapper +template +class property_wrapper : public property_wrapper_base, public metadata_handler { using return_type = typename function_traits::return_type; public: property_wrapper(string_view name, Getter get, std::array metadata_list) RTTR_NOEXCEPT - : property_wrapper_base(name, type::get()), + : property_wrapper_base(name, type::get()), metadata_handler(std::move(metadata_list)), m_accessor(get) { @@ -247,7 +247,7 @@ class property_wrapper(prop, m_accessor); + auto obj = make_property_info(prop, m_accessor); visitor_iterator::visit(visitor, make_property_visitor_invoker(obj)); } @@ -259,8 +259,8 @@ class property_wrapper -class property_wrapper +template +class property_wrapper : public property_wrapper_base, public metadata_handler { using return_type = typename function_traits::return_type; @@ -270,7 +270,7 @@ class property_wrapper metadata_list) RTTR_NOEXCEPT - : property_wrapper_base(name, type::get()), + : property_wrapper_base(name, type::get()), metadata_handler(std::move(metadata_list)), m_getter(get), m_setter(set) { @@ -311,7 +311,7 @@ class property_wrapper(prop, m_getter, m_setter); + auto obj = make_property_getter_setter_info(prop, m_getter, m_setter); visitor_iterator::visit(visitor, make_property_getter_setter_visitor_invoker(obj)); } @@ -324,8 +324,8 @@ class property_wrapper -class property_wrapper +template +class property_wrapper : public property_wrapper_base, public metadata_handler { using return_type = typename function_traits::return_type; @@ -334,7 +334,7 @@ class property_wrapper metadata_list) RTTR_NOEXCEPT - : property_wrapper_base(name, type::get()), + : property_wrapper_base(name, type::get()), metadata_handler(std::move(metadata_list)), m_accessor(get) { @@ -363,7 +363,7 @@ class property_wrapper(prop, m_accessor); + auto obj = make_property_info(prop, m_accessor); visitor_iterator::visit(visitor, make_property_visitor_invoker(obj)); } diff --git a/src/rttr/detail/property/property_wrapper_member_functor.h b/src/rttr/detail/property/property_wrapper_member_functor.h new file mode 100644 index 00000000..400a8f24 --- /dev/null +++ b/src/rttr/detail/property/property_wrapper_member_functor.h @@ -0,0 +1,398 @@ +/************************************************************************************ +* * +* Copyright (c) 2014 - 2018 Axel Menzel * +* * +* This file is part of RTTR (Run Time Type Reflection) * +* License: MIT License * +* * +* Permission is hereby granted, free of charge, to any person obtaining * +* a copy of this software and associated documentation files (the "Software"), * +* to deal in the Software without restriction, including without limitation * +* the rights to use, copy, modify, merge, publish, distribute, sublicense, * +* and/or sell copies of the Software, and to permit persons to whom the * +* Software is furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included in * +* all copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * +* SOFTWARE. * +* * +*************************************************************************************/ + +#ifndef RTTR_PROPERTY_WRAPPER_FUNCTOR_H_ +#define RTTR_PROPERTY_WRAPPER_FUNCTOR_H_ + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// global function getter/setter - function pointer + +template +class property_wrapper + : public property_wrapper_base, public metadata_handler +{ + using return_type = typename function_traits::return_type; + using arg_type = typename param_types::type; + + public: + property_wrapper(string_view name, + Getter get, Setter set, + std::array metadata_list) RTTR_NOEXCEPT + : property_wrapper_base(name, type::get()), + metadata_handler(std::move(metadata_list)), + m_getter(get), m_setter(set) + { + static_assert(function_traits::arg_count == 1, "Invalid number of argument, please provide a getter-functor with a self argument."); + static_assert(function_traits::arg_count == 2, "Invalid number of argument, please provide a setter-functor with self and value arguments."); + static_assert(std::is_same::value, "Please provide the same signature for getter and setter!"); + + init(); + } + + access_levels get_access_level() const RTTR_NOEXCEPT { return Acc_Level; } + bool is_valid() const RTTR_NOEXCEPT { return true; } + bool is_readonly() const RTTR_NOEXCEPT { return false; } + bool is_static() const RTTR_NOEXCEPT { return false; } + type get_type() const RTTR_NOEXCEPT { return type::get(); } + + variant get_metadata(const variant& key) const { return metadata_handler::get_metadata(key); } + + bool set_value(instance& object, argument& arg) const + { + Declaring_Typ* ptr = object.try_convert(); + if (ptr && arg.is_type()) + { + m_setter(ptr, arg.get_value()); + return true; + } + return false; + } + + variant get_value(instance& object) const + { + if (Declaring_Typ* ptr = object.try_convert()) + return variant(m_getter(ptr)); + else + return variant(); + } + + void visit(visitor& visitor, property prop) const RTTR_NOEXCEPT + { + auto obj = make_property_getter_setter_info(prop, m_getter, m_setter); + visitor_iterator::visit(visitor, make_property_getter_setter_visitor_invoker(obj)); + } + + private: + Getter m_getter; + Setter m_setter; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// global function getter + +template +class property_wrapper + : public property_wrapper_base, public metadata_handler +{ + using return_type = typename function_traits::return_type; + + public: + property_wrapper(string_view name, + Getter get, std::array metadata_list) RTTR_NOEXCEPT + : property_wrapper_base(name, type::get()), + metadata_handler(std::move(metadata_list)), + m_accessor(get) + { + static_assert(function_traits::arg_count == 1, "Invalid number of argument, please provide a getter-functor with a self argument."); + + init(); + } + + access_levels get_access_level() const RTTR_NOEXCEPT { return Acc_Level; } + bool is_valid() const RTTR_NOEXCEPT { return true; } + bool is_readonly() const RTTR_NOEXCEPT { return true; } + bool is_static() const RTTR_NOEXCEPT { return false; } + type get_type() const RTTR_NOEXCEPT { return type::get(); } + bool is_array() const RTTR_NOEXCEPT { return std::is_array::value; } + + variant get_metadata(const variant& key) const { return metadata_handler::get_metadata(key); } + + bool set_value(instance& object, argument& arg) const + { + return false; + } + + variant get_value(instance& object) const + { + if (Declaring_Typ* ptr = object.try_convert()) + return variant(m_accessor(ptr)); + else + return variant(); + } + + void visit(visitor& visitor, property prop) const RTTR_NOEXCEPT + { + auto obj = make_property_info(prop, m_accessor); + visitor_iterator::visit(visitor, make_property_visitor_invoker(obj)); + } + + private: + Getter m_accessor; +}; + + + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// global function getter/setter + +template +class property_wrapper + : public property_wrapper_base, public metadata_handler +{ + using return_type = typename function_traits::return_type; + using arg_type = typename param_types::type; + + public: + property_wrapper(string_view name, + Getter get, Setter set, + std::array metadata_list) RTTR_NOEXCEPT + : property_wrapper_base(name, type::get()), + metadata_handler(std::move(metadata_list)), + m_getter(get), m_setter(set) + { + static_assert(std::is_reference::value, "Please provide a getter-function with a reference as return value!"); + static_assert(std::is_reference::value, "Please provide a setter-function with a reference as argument!"); + + static_assert(function_traits::arg_count == 1, "Invalid number of argument, please provide a getter-functor with a self argument."); + static_assert(function_traits::arg_count == 2, "Invalid number of argument, please provide a setter-functor with self and value arguments."); + + static_assert(std::is_same::value, "Please provide the same signature for getter and setter!"); + + init(); + } + + access_levels get_access_level() const RTTR_NOEXCEPT { return Acc_Level; } + bool is_valid() const RTTR_NOEXCEPT { return true; } + bool is_readonly() const RTTR_NOEXCEPT { return false; } + bool is_static() const RTTR_NOEXCEPT { return false; } + type get_type() const RTTR_NOEXCEPT { return type::get::type*>(); } + + variant get_metadata(const variant& key) const { return metadata_handler::get_metadata(key); } + + bool set_value(instance& object, argument& arg) const + { + Declaring_Typ* ptr = object.try_convert(); + using arg_type_t = remove_reference_t; + if (ptr && arg.is_type()) + { + m_setter(ptr, *arg.get_value()); + return true; + } + return false; + } + + variant get_value(instance& object) const + { + if (Declaring_Typ* ptr = object.try_convert()) + return variant(&(m_getter(ptr))); + else + return variant(); + } + + void visit(visitor& visitor, property prop) const RTTR_NOEXCEPT + { + auto obj = make_property_getter_setter_info(prop, m_getter, m_setter); + visitor_iterator::visit(visitor, make_property_getter_setter_visitor_invoker(obj)); + } + + private: + Getter m_getter; + Setter m_setter; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// global function getter + +template +class property_wrapper + : public property_wrapper_base, public metadata_handler +{ + using return_type = typename function_traits::return_type; + public: + property_wrapper(string_view name, + Getter get, std::array metadata_list) RTTR_NOEXCEPT + : property_wrapper_base(name, type::get()), + metadata_handler(std::move(metadata_list)), + m_accessor(get) + { + static_assert(function_traits::arg_count == 1, "Invalid number of argument, please provide a getter-functor with a self argument."); + static_assert(std::is_reference::value, "Please provide a function with a reference as return value!"); + + init(); + } + + access_levels get_access_level() const RTTR_NOEXCEPT { return Acc_Level; } + bool is_valid() const RTTR_NOEXCEPT { return true; } + bool is_readonly() const RTTR_NOEXCEPT { return true; } + bool is_static() const RTTR_NOEXCEPT { return false; } + type get_type() const RTTR_NOEXCEPT { return type::get::type>::type*>(); } + + variant get_metadata(const variant& key) const { return metadata_handler::get_metadata(key); } + + bool set_value(instance& object, argument& arg) const + { + return false; + } + + variant get_value(instance& object) const + { + if (Declaring_Typ* ptr = object.try_convert()) + return (variant(const_cast::type*>(&(m_accessor(ptr))))); + else + return variant(); + } + + void visit(visitor& visitor, property prop) const RTTR_NOEXCEPT + { + auto obj = make_property_info(prop, m_accessor); + visitor_iterator::visit(visitor, make_property_visitor_invoker(obj)); + } + + private: + Getter m_accessor; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// global function getter/setter + +template +class property_wrapper + : public property_wrapper_base, public metadata_handler +{ + using return_type = typename function_traits::return_type; + using arg_type = typename param_types::type; + + public: + property_wrapper(string_view name, + Getter get, Setter set, + std::array metadata_list) RTTR_NOEXCEPT + : property_wrapper_base(name, type::get()), + metadata_handler(std::move(metadata_list)), + m_getter(get), m_setter(set) + { + static_assert(std::is_reference::value, "Please provide a getter-function with a reference as return value!"); + static_assert(std::is_reference::value, "Please provide a setter-function with a reference as argument!"); + + static_assert(function_traits::arg_count == 1, "Invalid number of argument, please provide a getter-functor with a self argument."); + static_assert(function_traits::arg_count == 2, "Invalid number of argument, please provide a setter-functor with self and value arguments."); + + static_assert(std::is_same::value, "Please provide the same signature for getter and setter!"); + + init(); + } + + access_levels get_access_level() const RTTR_NOEXCEPT { return Acc_Level; } + bool is_valid() const RTTR_NOEXCEPT { return true; } + bool is_readonly() const RTTR_NOEXCEPT { return false; } + bool is_static() const RTTR_NOEXCEPT { return false; } + type get_type() const RTTR_NOEXCEPT { return type::get< std::reference_wrapper> >(); } + + variant get_metadata(const variant& key) const { return metadata_handler::get_metadata(key); } + + bool set_value(instance& object, argument& arg) const + { + Declaring_Typ* ptr = object.try_convert(); + using arg_type_t = remove_reference_t; + if (ptr && arg.is_type>()) + { + m_setter(ptr, arg.get_value>().get()); + return true; + } + return false; + } + + variant get_value(instance& object) const + { + if (Declaring_Typ* ptr = object.try_convert()) + return variant(std::ref(m_getter(ptr))); + else + return variant(); + } + + void visit(visitor& visitor, property prop) const RTTR_NOEXCEPT + { + auto obj = make_property_getter_setter_info(prop, m_getter, m_setter); + visitor_iterator::visit(visitor, make_property_getter_setter_visitor_invoker(obj)); + } + + private: + Getter m_getter; + Setter m_setter; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +// global function getter + +template +class property_wrapper + : public property_wrapper_base, public metadata_handler +{ + using return_type = typename function_traits::return_type; + using policy_type = std::reference_wrapper>>; + + public: + property_wrapper(string_view name, + Getter get, std::array metadata_list) RTTR_NOEXCEPT + : property_wrapper_base(name, type::get()), + metadata_handler(std::move(metadata_list)), + m_accessor(get) + { + static_assert(function_traits::arg_count == 1, "Invalid number of argument, please provide a getter-functor with a self argument."); + static_assert(std::is_reference::value, "Please provide a function with a reference as return value!"); + + init(); + } + + access_levels get_access_level() const RTTR_NOEXCEPT { return Acc_Level; } + bool is_valid() const RTTR_NOEXCEPT { return true; } + bool is_readonly() const RTTR_NOEXCEPT { return true; } + bool is_static() const RTTR_NOEXCEPT { return false; } + type get_type() const RTTR_NOEXCEPT { return type::get(); } + + variant get_metadata(const variant& key) const { return metadata_handler::get_metadata(key); } + + bool set_value(instance& object, argument& arg) const + { + return false; + } + + variant get_value(instance& object) const + { + if (Declaring_Typ* ptr = object.try_convert()) + return variant(std::cref(m_accessor(ptr))); + else + return variant(); + } + + void visit(visitor& visitor, property prop) const RTTR_NOEXCEPT + { + auto obj = make_property_info(prop, m_accessor); + visitor_iterator::visit(visitor, make_property_visitor_invoker(obj)); + } + + private: + Getter m_accessor; +}; + + +#endif // RTTR_PROPERTY_WRAPPER_FUNCTOR_H_ diff --git a/src/rttr/detail/registration/registration_impl.h b/src/rttr/detail/registration/registration_impl.h index dc3d3240..0887b57e 100644 --- a/src/rttr/detail/registration/registration_impl.h +++ b/src/rttr/detail/registration/registration_impl.h @@ -193,14 +193,6 @@ registration::bind re static_assert(std::is_member_function_pointer::value || std::is_member_function_pointer::value || is_functor::value || is_functor::value, "No valid property accessor provided!"); - static_assert(function_traits::arg_count == 0, "Invalid number of arguments, please provide as first accessor a getter-member-function without arguments."); - static_assert(function_traits::arg_count == 1, "Invalid number of arguments, please provide as second argument a setter-member-function with exactly one argument."); - using return_type = typename function_traits::return_type; - using arg_type = typename param_types::type; - static_assert(std::is_same::type>::type>::type, - typename std::remove_const::type>::type>::type>::value, - "Please provide the same signature (data type) for getter and setter!"); - return {create_if_empty(m_reg_exec), name, getter, setter}; } diff --git a/src/unit_tests/property/property_member_function.cpp b/src/unit_tests/property/property_member_function.cpp index 7a5e5e49..074237e0 100644 --- a/src/unit_tests/property/property_member_function.cpp +++ b/src/unit_tests/property/property_member_function.cpp @@ -66,10 +66,16 @@ static void my_callback(int) { } +int int_getter_global(property_member_func_test* self) { return self->get_int_value(); } +void int_setter_global(property_member_func_test* self, int value) { self->get_int_ref() = value; } + ///////////////////////////////////////////////////////////////////////////////////////// RTTR_REGISTRATION { + int i = 3; + auto int_getter = [i](property_member_func_test* self) { return self->get_int_value(); }; + auto int_setter = [i](property_member_func_test* self, int value) { self->get_int_ref() = value; }; registration::class_("property_member_func_test") .property("p1", &property_member_func_test::get_text, &property_member_func_test::set_text) ( @@ -79,6 +85,9 @@ RTTR_REGISTRATION ( metadata("Description", "Some Text") ) + .property_readonly("p2_lambda", int_getter) + .property_readonly("p2_global", int_getter_global) + .property_readonly("p2_function", std::function(int_getter)) .property("p3", &property_member_func_test::get_text, &property_member_func_test::set_text) ( metadata("Description", "Some Text"), @@ -100,6 +109,9 @@ RTTR_REGISTRATION metadata("Description", "Some Text"), policy::prop::as_reference_wrapper ) + .property("p7_lambda", int_getter, int_setter) + .property("p7_global", int_getter_global, int_setter_global) + .property("p7_function", std::function(int_getter), std::function(int_setter)) ; } @@ -161,6 +173,35 @@ TEST_CASE("property - class function - read only", "[property]") ///////////////////////////////////////////////////////////////////////////////////////// +TEST_CASE("property - functors - read only", "[property]") +{ + property_member_func_test obj; + type prop_type = type::get(obj); + + for (const char* name : { "p2_lambda", "p2_global", "p2_function" }) + { + property prop = prop_type.get_property(name); + REQUIRE(prop.is_valid() == true); + + // metadata + CHECK(prop.is_readonly() == true); + CHECK(prop.is_static() == false); + CHECK(prop.get_type() == type::get()); + CHECK(prop.get_access_level() == rttr::access_levels::public_access); + + // invoke + CHECK(prop.get_value(obj).is_type() == true); + CHECK(prop.get_value(obj).get_value() == 12); + + // invalid invoke + CHECK(prop.set_value(obj, 23) == false); + CHECK(prop.get_value(g_invalid_instance).is_valid() == false); + + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + TEST_CASE("property - class function - bind as ptr", "[property]") { property_member_func_test obj; @@ -216,6 +257,35 @@ TEST_CASE("property - class function - read only - bind as ptr", "[property]") CHECK(prop.get_value(g_invalid_instance).is_valid() == false); } +TEST_CASE("property - functors", "[property]") +{ + for (const char* name : { "p7_lambda", "p7_global", "p7_function" }) + { + property_member_func_test obj; + type prop_type = type::get(obj); + + property prop = prop_type.get_property(name); + REQUIRE(prop.is_valid() == true); + + // metadata + CHECK(prop.is_readonly() == false); + CHECK(prop.is_static() == false); + + CHECK(prop.get_type() == type::get()); + CHECK(prop.get_access_level() == rttr::access_levels::public_access); + + // invoke get + REQUIRE(prop.get_value(obj).is_type() == true); + CHECK(prop.get_value(obj).get_value() == 12); + + // invoke set + CHECK(prop.set_value("wrong instance", 23) == false); + REQUIRE(prop.set_value(obj, 23) == true); + REQUIRE(prop.get_value(obj).is_type() == true); + CHECK(prop.get_value(obj).get_value() == 23); + } +} + ///////////////////////////////////////////////////////////////////////////////////////// TEST_CASE("property - class function - function pointer", "[property]")