From accf8f06eae927de843ee359b47ef152e1a8bd57 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 10:56:30 -0400 Subject: [PATCH 1/4] Add reflector_verifier_visitor for classes that wish to validate reflection serialization --- include/fc/reflect/reflect.hpp | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/include/fc/reflect/reflect.hpp b/include/fc/reflect/reflect.hpp index bf68d17c3..25216e2f0 100644 --- a/include/fc/reflect/reflect.hpp +++ b/include/fc/reflect/reflect.hpp @@ -158,6 +158,21 @@ struct reflector{ * }; * @endcode * + * If reflection requires a verification (what a constructor might normally assert) then + * derive your Visitor from reflector_verifier_visitor and implement a reflector_verify() + * on your reflected type. + * + * @code + * template + * struct functor : reflector_verifier_visitor { + * functor(Class& _c) + * : fc::reflector_verifier_visitor(_c) {} + * + * template + * void operator()( const char* name )const; + * }; + * @endcode + * * If T is an enum then the functor has the following form: * @code * struct functor { @@ -178,6 +193,37 @@ struct reflector{ void throw_bad_enum_cast( int64_t i, const char* e ); void throw_bad_enum_cast( const char* k, const char* e ); + +template +struct reflector_verifier_visitor { + explicit reflector_verifier_visitor( Class& c ) + : obj(c) {} + + ~reflector_verifier_visitor() noexcept(false) { + verify( obj ); + } + + private: + + // int matches 0 if reflector_verify exists SFINAE + template + auto verify_imp(const T& t, int) -> decltype(t.reflector_verify(), void()) { + t.reflector_verify(); + } + + // if no reflector_verify method exists (SFINAE), 0 matches long + template + auto verify_imp(const T& t, long) -> decltype(t, void()) {} + + template + auto verify(const T& t) -> decltype(verify_imp(t, 0), void()) { + verify_imp(t, 0); + } + + protected: + Class& obj; +}; + } // namespace fc From 4219caa13986fa4247828597e9df99d9772c9f1b Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 10:58:31 -0400 Subject: [PATCH 2/4] Add usage of new reflector_verifier_visitor --- include/fc/io/raw.hpp | 9 +++++---- include/fc/reflect/variant.hpp | 7 +++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/fc/io/raw.hpp b/include/fc/io/raw.hpp index 6b0371b55..16adec435 100644 --- a/include/fc/io/raw.hpp +++ b/include/fc/io/raw.hpp @@ -339,8 +339,9 @@ namespace fc { }; template - struct unpack_object_visitor { - unpack_object_visitor( Class& _c, Stream& _s, uint32_t _max_depth ) : c(_c),s(_s),max_depth(_max_depth - 1) + struct unpack_object_visitor : fc::reflector_verifier_visitor { + unpack_object_visitor( Class& _c, Stream& _s, uint32_t _max_depth ) + : fc::reflector_verifier_visitor(_c), s(_s), max_depth(_max_depth - 1) { FC_ASSERT( _max_depth > 0 ); } @@ -348,10 +349,10 @@ namespace fc { template inline void operator()( const char* name )const { try { - fc::raw::unpack( s, c.*p, max_depth ); + fc::raw::unpack( s, this->obj.*p, max_depth ); } FC_RETHROW_EXCEPTIONS( warn, "Error unpacking field ${field}", ("field",name) ) } + private: - Class& c; Stream& s; const uint32_t max_depth; }; diff --git a/include/fc/reflect/variant.hpp b/include/fc/reflect/variant.hpp index 8f88dc99d..e812d2a37 100644 --- a/include/fc/reflect/variant.hpp +++ b/include/fc/reflect/variant.hpp @@ -42,11 +42,11 @@ namespace fc }; template - class from_variant_visitor + class from_variant_visitor : reflector_verifier_visitor { public: from_variant_visitor( const variant_object& _vo, T& v, uint32_t max_depth ) - :vo(_vo),val(v),_max_depth(max_depth - 1) { + : reflector_verifier_visitor(v), vo(_vo), _max_depth(max_depth - 1) { _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); } @@ -55,11 +55,10 @@ namespace fc { auto itr = vo.find(name); if( itr != vo.end() ) - from_variant( itr->value(), val.*member, _max_depth ); + from_variant( itr->value(), this->obj.*member, _max_depth ); } const variant_object& vo; - T& val; const uint32_t _max_depth; }; From e11ad145718a3814db7a8b8e010239e8cc988d8c Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 22 May 2018 14:32:51 -0400 Subject: [PATCH 3/4] Move call of object reflector_verify from visitor destructor to explicit call in visit --- include/fc/reflect/reflect.hpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/include/fc/reflect/reflect.hpp b/include/fc/reflect/reflect.hpp index 25216e2f0..71d6bf986 100644 --- a/include/fc/reflect/reflect.hpp +++ b/include/fc/reflect/reflect.hpp @@ -199,8 +199,8 @@ struct reflector_verifier_visitor { explicit reflector_verifier_visitor( Class& c ) : obj(c) {} - ~reflector_verifier_visitor() noexcept(false) { - verify( obj ); + void reflector_verify() { + reflect_verify( obj ); } private: @@ -216,7 +216,7 @@ struct reflector_verifier_visitor { auto verify_imp(const T& t, long) -> decltype(t, void()) {} template - auto verify(const T& t) -> decltype(verify_imp(t, 0), void()) { + auto reflect_verify(const T& t) -> decltype(verify_imp(t, 0), void()) { verify_imp(t, 0); } @@ -255,6 +255,7 @@ template\ static inline void visit( const Visitor& v ) { \ BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_BASE, v, INHERITS ) \ BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_VISIT_MEMBER, v, MEMBERS ) \ + verify( v ); \ } #endif // DOXYGEN @@ -362,6 +363,16 @@ template<> struct reflector {\ using members = typename typelist::concat::type; \ using base_classes = typename typelist::builder<>::type \ BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \ + template \ + static auto verify_imp(const Visitor& v, int) -> decltype(v.reflector_verify(), void()) { \ + v.reflector_verify(); \ + } \ + template \ + static auto verify_imp(const Visitor& v, long) -> decltype(v, void()) {} \ + template \ + static auto verify(const Visitor& v) -> decltype(verify_imp(v, 0), void()) { \ + verify_imp(v, 0); \ + } \ enum member_count_enum { \ local_member_count = typelist::length(), \ total_member_count = typelist::length() \ @@ -389,6 +400,16 @@ template struct reflector {\ using members = typename typelist::concat::type; \ using base_classes = typename typelist::builder<>::type \ BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \ + template \ + static auto verify_imp(const Visitor& v, int) -> decltype(v.reflector_verify(), void()) { \ + v.reflector_verify(); \ + } \ + template \ + static auto verify_imp(const Visitor& v, long) -> decltype(v, void()) {} \ + template \ + static auto verify(const Visitor& v) -> decltype(verify_imp(v, 0), void()) { \ + verify_imp(v, 0); \ + } \ enum member_count_enum { \ local_member_count = typelist::length(), \ total_member_count = typelist::length() \ From f2629b1eeef0b073c42119d6bbe3683dade819fe Mon Sep 17 00:00:00 2001 From: Peter Conrad Date: Tue, 24 Sep 2019 17:02:24 +0200 Subject: [PATCH 4/4] Add verify() to FC_REFLECT_DERIVED_NO_TYPENAME macro --- include/fc/reflect/reflect.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/fc/reflect/reflect.hpp b/include/fc/reflect/reflect.hpp index 71d6bf986..2a04e4b11 100644 --- a/include/fc/reflect/reflect.hpp +++ b/include/fc/reflect/reflect.hpp @@ -434,6 +434,16 @@ template<> struct reflector {\ using members = typename typelist::concat::type; \ using base_classes = typename typelist::builder<>::type \ BOOST_PP_SEQ_FOR_EACH( FC_CONCAT_TYPE, x, INHERITS ) ::finalize; \ + template \ + static auto verify_imp(const Visitor& v, int) -> decltype(v.reflector_verify(), void()) { \ + v.reflector_verify(); \ + } \ + template \ + static auto verify_imp(const Visitor& v, long) -> decltype(v, void()) {} \ + template \ + static auto verify(const Visitor& v) -> decltype(verify_imp(v, 0), void()) { \ + verify_imp(v, 0); \ + } \ enum member_count_enum { \ local_member_count = typelist::length(), \ total_member_count = typelist::length() \