#pragma once #include #include #include #include #include #include namespace fc { template T value_cast( const value& v ); struct void_t{}; template void pack(fc::value& jsv, const T& v ); template void unpack( const fc::value& jsv, T& v ); template void pack( fc::value& v, const tuple& t ); template void unpack( const fc::value& val, tuple& t ); template void pack( fc::value& jsv, const fc::optional& v ); template void unpack( const fc::value& jsv, fc::optional& v ); inline void pack( fc::value& jsv, const char& v ) { jsv = fc::string(&v,1); } inline void pack( fc::value& jsv, const fc::value& v ) { jsv = v; } inline void pack( fc::value& jsv, fc::value& v ) { jsv = v; } inline void pack( fc::value& jsv, fc::value&& v ) { jsv = fc::move(v); } inline void pack( fc::value& jsv, const void_t& v ) { jsv = fc::value(); } inline void pack( fc::value& jsv, const bool& v ) { jsv = v; } inline void pack( fc::value& jsv, const float& v ) { jsv = v; } inline void pack( fc::value& jsv, const double& v ) { jsv = v; } inline void pack( fc::value& jsv, const uint8_t& v ) { jsv = v; } inline void pack( fc::value& jsv, const uint16_t& v ) { jsv = v; } inline void pack( fc::value& jsv, const uint32_t& v ) { jsv = v; } inline void pack( fc::value& jsv, const uint64_t& v ) { jsv = v; } inline void pack( fc::value& jsv, const int8_t& v ) { jsv = v; } inline void pack( fc::value& jsv, const int16_t& v ) { jsv = v; } inline void pack( fc::value& jsv, const int32_t& v ) { jsv = v; } inline void pack( fc::value& jsv, const int64_t& v ) { jsv = v; } inline void pack( fc::value& jsv, const fc::string& v ) { jsv = value(v); } inline void pack( fc::value& jsv, fc::string& v ) { jsv = v; } inline void pack( fc::value& jsv, fc::string&& v ) { jsv = fc::move(v); } inline void pack( fc::value& jsv, const char* v ) { jsv = fc::string(v); } void pack( fc::value& jsv, const fc::vector& value ); template void pack( fc::value& jsv, const fc::vector& value ); inline void unpack( const fc::value& jsv, fc::value& v ) { v = jsv; } template void unpack( const fc::value& jsv, const T& v ); template void unpack( const fc::value& jsv, T& v ); void unpack( const fc::value& jsv, bool& v ); inline void unpack( const fc::value& jsv, void_t& v ){ }; void unpack( const fc::value& jsv, float& v ); void unpack( const fc::value& jsv, double& v ); void unpack( const fc::value& jsv, uint8_t& v ); void unpack( const fc::value& jsv, uint16_t& v ); void unpack( const fc::value& jsv, uint32_t& v ); void unpack( const fc::value& jsv, uint64_t& v ); void unpack( const fc::value& jsv, int8_t& v ); void unpack( const fc::value& jsv, int16_t& v ); void unpack( const fc::value& jsv, int32_t& v ); void unpack( const fc::value& jsv, int64_t& v ); void unpack( const fc::value& jsv, fc::string& v ); void unpack( const fc::value& jsv, fc::vector& value ); void unpack( const fc::value& jsv, fc::vector& value ); template void unpack( const fc::value& jsv, fc::vector& value ); namespace detail { template struct pack_object_visitor { pack_object_visitor(const Class& _c, fc::value& _val) :c(_c),obj(_val){} /** VC++ does not understand the difference of return types, so an extra layer is needed. */ template inline void pack_helper( const T& v, const char* name )const { value* o = &obj[name]; fc::pack( *o, v ); } template inline void pack_helper( const fc::optional& v, const char* name )const { if( !!v ) { fc::pack( obj[name], *v ); } } template inline void operator()( const char* name )const { pack_helper( c.*p, name ); } private: const Class& c; fc::value& obj; }; template struct is_optional { typedef fc::false_type type; }; template struct is_optional > { typedef fc::true_type type; }; template struct unpack_object_visitor { unpack_object_visitor(Class& _c, const fc::value& _val) :c(_c),obj(_val){} template void operator()( const char* name )const { if( obj.find(name) != obj.end()) { try { fc::unpack( obj[name], c.*p ); } catch ( fc::error_report& er ) { throw FC_REPORT_PUSH( er, "Error parsing field '${field_name}'", fc::value().set("field_name",name) ); } } else { if( !is_optional< typename fc::remove_reference::type >::type::value ) { wlog( "unable to find name: '%s'",name); } } } Class& c; const fc::value& obj; }; template struct if_enum { template static inline void pack( fc::value& jsv, const T& v ) { jsv = fc::value::object(); detail::pack_object_visitor pov(v,jsv); fc::reflector::visit(pov); } template static inline void unpack( const fc::value& jsv, T& v ) { detail::unpack_object_visitor pov(v,jsv ); fc::reflector::visit(pov); } }; template<> struct if_enum { template static inline void pack( fc::value& jsv, const T& v ) { fc::pack( jsv, fc::reflector::to_string(v) ); } template static inline void unpack( const fc::value& jsv, T& v ) { if( strcmp( jsv.type(), "string" ) == 0 ) { v = fc::reflector::from_string( fc::value_cast(jsv).c_str() ); } else { // throw if invalid int, by attempting to convert to string fc::reflector::to_string( v = static_cast(value_cast(jsv)) ); } } }; template struct if_reflected { template static inline void pack(fc::value& s, const T& v ) { v.did_not_implement_reflect_macro(); wlog( "warning, ignoring unknown type" ); } template static inline void unpack( const fc::value& s, T& v ) { v.did_not_implement_reflect_macro(); wlog( "warning, ignoring unknown type" ); } }; template<> struct if_reflected { template static inline void pack( fc::value& jsv, const T& v ) { if_enum::is_enum>::pack( jsv,v ); } template static inline void unpack( const fc::value& jsv, T& v ) { if_enum::is_enum>::unpack( jsv,v ); } }; } // namesapce detail inline void unpack( const fc::value& jsv, char& v ) { auto s = value_cast(jsv); if( s.size() ) v = s[0]; } inline void unpack( const fc::value& jsv, bool& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, float& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, double& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, uint8_t& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, uint16_t& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, uint32_t& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, uint64_t& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, int8_t& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, int16_t& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, int32_t& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, int64_t& v ) { v = value_cast(jsv); } inline void unpack( const fc::value& jsv, fc::string& v ) { v = value_cast(jsv); } template void pack( fc::value& jsv, const fc::optional& v ) { if( v ) pack( jsv, *v ); else jsv = fc::value(); } template void unpack( const fc::value& jsv, fc::optional& v ) { if( strcmp( jsv.type(), "void" ) != 0 ) { T tmp; unpack( jsv, tmp ); v = fc::move(tmp); } } template inline void pack( fc::value& jsv, const fc::vector& value ) { jsv = fc::value::array(); jsv.resize(value.size()); typename fc::vector::const_iterator itr = value.begin(); typename fc::vector::const_iterator end = value.end(); uint32_t i = 0; while( itr != end ) { fc::pack( jsv[i], *itr ); ++itr; ++i; } } struct tuple_to_value_visitor { tuple_to_value_visitor( value& v ):_val(v),_count(0) { } template void operator()( T&& t ) { _val[_count] = value(fc::forward(t) ); ++_count; } value& _val; int _count; }; struct tuple_from_value_visitor { tuple_from_value_visitor( const value& v ):_val(v),_count(0) { } template void operator()( T&& t ) { if( _count < _val.size() ) unpack( _val[_count], t ); ++_count; } const value& _val; int _count; }; template inline void pack( fc::value& val, const tuple& t ) { val = fc::value::array( tuple::size ); t.visit( tuple_to_value_visitor(val) ); } template inline void unpack( const fc::value& val, tuple& t ) { t.visit( tuple_from_value_visitor(val) ); } template inline void unpack( const fc::value& jsv, fc::vector& val ) { val.resize( jsv.size() ); uint32_t s = jsv.size(); for( uint32_t i = 0; i < s; ++i ) { unpack( jsv[i], val[i] ); } } // default case template inline void pack( fc::value& jsv, const T& v ) { detail::if_reflected< typename fc::reflector::is_defined >::pack(jsv,v); } template inline void unpack( const fc::value& jsv, T& v ) { detail::if_reflected< typename fc::reflector::is_defined >::unpack(jsv,v); } } // namespace fc