diff --git a/libraries/libfc/include/fc/io/raw.hpp b/libraries/libfc/include/fc/io/raw.hpp index b00c9da1f4..cc4317f797 100644 --- a/libraries/libfc/include/fc/io/raw.hpp +++ b/libraries/libfc/include/fc/io/raw.hpp @@ -36,10 +36,15 @@ namespace fc { template void unpack( Stream& s, boost::multiprecision::number& n ); template - inline void pack( Stream& s, const Arg0& a0, Args... args ) { + inline void pack( Stream& s, const Arg0& a0, const Args&... args ) { pack( s, a0 ); pack( s, args... ); } + template + inline void unpack( Stream& s, Arg0& a0, Args&... args ) { + unpack( s, a0 ); + unpack( s, args... ); + } template inline void pack( Stream& s, const fc::exception& e ) @@ -243,7 +248,12 @@ namespace fc { FC_ASSERT( vi == tmp ); } - template inline void pack( Stream& s, const char* v ) { fc::raw::pack( s, std::string(v) ); } + template inline void pack( Stream& s, const char* v ) { + size_t sz = std::strlen(v); + FC_ASSERT( sz <= MAX_SIZE_OF_BYTE_ARRAYS ); + fc::raw::pack( s, unsigned_int(sz)); + if( sz ) s.write( v, sz ); + } template void pack( Stream& s, const safe& v ) { fc::raw::pack( s, v.value ); } @@ -442,6 +452,16 @@ namespace fc { } } + template + inline void pack( Stream& s, const std::tuple& tup ) { + auto l = [&s](const auto&... v) { fc::raw::pack( s, v... ); }; + std::apply(l, tup); + } + template + inline void unpack( Stream& s, std::tuple& tup ) { + auto l = [&s](auto&... v) { fc::raw::unpack( s, v... ); }; + std::apply(l, tup); + } template inline void pack( Stream& s, const std::pair& value ) { diff --git a/libraries/libfc/test/network/test_message_buffer.cpp b/libraries/libfc/test/network/test_message_buffer.cpp index 5e603b32bd..8a6ab2adb6 100644 --- a/libraries/libfc/test/network/test_message_buffer.cpp +++ b/libraries/libfc/test/network/test_message_buffer.cpp @@ -344,6 +344,57 @@ BOOST_AUTO_TEST_CASE(message_buffer_datastream) { } } +BOOST_AUTO_TEST_CASE(message_buffer_datastream_tuple) { + using my_message_buffer_t = fc::message_buffer<1024>; + my_message_buffer_t mbuff; + + char buf[1024]; + fc::datastream ds( buf, 1024 ); + + using my_tuple = std::tuple; + my_tuple t(13, 42, "hello"); + fc::raw::pack( ds, t ); + + memcpy(mbuff.write_ptr(), buf, 1024); + mbuff.advance_write_ptr(1024); + + for( int i = 0; i < 3; ++i ) { + auto ds2 = mbuff.create_peek_datastream(); + my_tuple t2; + fc::raw::unpack( ds2, t2 ); + BOOST_CHECK( t == t2 ); + } + + { + auto ds2 = mbuff.create_datastream(); + my_tuple t2; + fc::raw::unpack( ds2, t2 ); + BOOST_CHECK( t == t2 ); + } +} + +BOOST_AUTO_TEST_CASE(message_buffer_datastream_variadic_pack_unpack) { + using my_message_buffer_t = fc::message_buffer<1024>; + my_message_buffer_t mbuff; + + char buf[1024]; + fc::datastream ds( buf, 1024 ); + + using my_tuple = std::tuple; + my_tuple t(13, 42, "hello"); + fc::raw::pack( ds, std::get<0>(t), std::get<1>(t), std::get<2>(t) ); + + memcpy(mbuff.write_ptr(), buf, 1024); + mbuff.advance_write_ptr(1024); + + for( int i = 0; i < 3; ++i ) { + auto ds2 = mbuff.create_peek_datastream(); + my_tuple t2; + fc::raw::unpack( ds2, std::get<0>(t2), std::get<1>(t2), std::get<2>(t2) ); + BOOST_CHECK( t == t2 ); + } +} + // Make sure that the memory allocation is thread-safe. // A previous version used boost::object_pool without synchronization. BOOST_AUTO_TEST_CASE(test_message_buffer) {