From b9dca6977fdf1bfdc7eb8d92c2c538bf9e51beac Mon Sep 17 00:00:00 2001 From: Patrick Raphael Date: Tue, 22 Jun 2021 17:06:53 -0400 Subject: [PATCH 1/4] fix bug where params not present in trace due to exception being thrown by abi_serializer when no return data is present --- plugins/http_plugin/bind_handler.hpp | 132 ++++++ plugins/http_plugin/bind_handler_detail.hpp | 416 ++++++++++++++++++ plugins/trace_api_plugin/abi_data_handler.cpp | 14 +- 3 files changed, 557 insertions(+), 5 deletions(-) create mode 100644 plugins/http_plugin/bind_handler.hpp create mode 100644 plugins/http_plugin/bind_handler_detail.hpp diff --git a/plugins/http_plugin/bind_handler.hpp b/plugins/http_plugin/bind_handler.hpp new file mode 100644 index 00000000000..cfa6a74bf54 --- /dev/null +++ b/plugins/http_plugin/bind_handler.hpp @@ -0,0 +1,132 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_BIND_HANDLER_HPP +#define BOOST_BEAST_BIND_HANDLER_HPP + +#include +#include +#include +#include + +namespace boost { +namespace beast { + +/** Bind parameters to a completion handler, creating a new handler. + + This function creates a new handler which, when invoked, calls + the original handler with the list of bound arguments. Any + parameters passed in the invocation will be substituted for + placeholders present in the list of bound arguments. Parameters + which are not matched to placeholders are silently discarded. + + The passed handler and arguments are forwarded into the returned + handler, whose associated allocator and associated executor will + will be the same as those of the original handler. + + @par Example + + This function posts the invocation of the specified completion + handler with bound arguments: + + @code + template + void + signal_aborted (AsyncReadStream& stream, ReadHandler&& handler) + { + net::post( + stream.get_executor(), + bind_handler (std::forward (handler), + net::error::operation_aborted, 0)); + } + @endcode + + @param handler The handler to wrap. + The implementation takes ownership of the handler by performing a decay-copy. + + @param args A list of arguments to bind to the handler. + The arguments are forwarded into the returned object. These + arguments may include placeholders, which will operate in + a fashion identical to a call to `std::bind`. +*/ +template +#if BOOST_BEAST_DOXYGEN +__implementation_defined__ +#else +detail::bind_wrapper< + typename std::decay::type, + typename std::decay::type...> +#endif +bind_handler(Handler&& handler, Args&&... args) +{ + return detail::bind_wrapper< + typename std::decay::type, + typename std::decay::type...>( + std::forward(handler), + std::forward(args)...); +} + +/** Bind parameters to a completion handler, creating a new handler. + + This function creates a new handler which, when invoked, calls + the original handler with the list of bound arguments. Any + parameters passed in the invocation will be forwarded in + the parameter list after the bound arguments. + + The passed handler and arguments are forwarded into the returned + handler, whose associated allocator and associated executor will + will be the same as those of the original handler. + + @par Example + + This function posts the invocation of the specified completion + handler with bound arguments: + + @code + template + void + signal_eof (AsyncReadStream& stream, ReadHandler&& handler) + { + net::post( + stream.get_executor(), + bind_front_handler (std::forward (handler), + net::error::eof, 0)); + } + @endcode + + @param handler The handler to wrap. + The implementation takes ownership of the handler by performing a decay-copy. + + @param args A list of arguments to bind to the handler. + The arguments are forwarded into the returned object. +*/ +template +#if BOOST_BEAST_DOXYGEN +__implementation_defined__ +#else +auto +#endif +bind_front_handler( + Handler&& handler, + Args&&... args) -> + detail::bind_front_wrapper< + typename std::decay::type, + typename std::decay::type...> +{ + return detail::bind_front_wrapper< + typename std::decay::type, + typename std::decay::type...>( + std::forward(handler), + std::forward(args)...); +} + +} // beast +} // boost + +#endif diff --git a/plugins/http_plugin/bind_handler_detail.hpp b/plugins/http_plugin/bind_handler_detail.hpp new file mode 100644 index 00000000000..07db8d4b95b --- /dev/null +++ b/plugins/http_plugin/bind_handler_detail.hpp @@ -0,0 +1,416 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP +#define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace beast { +namespace detail { + +//------------------------------------------------------------------------------ +// +// bind_handler +// +//------------------------------------------------------------------------------ + +template +class bind_wrapper +{ + using args_type = detail::tuple; + + Handler h_; + args_type args_; + + template + friend struct net::associated_executor; + + template + friend struct net::associated_allocator; + + template + static + typename std::enable_if< + std::is_placeholder::type>::value == 0 && + boost::is_placeholder::type>::value == 0, + Arg&&>::type + extract(Arg&& arg, Vals&& vals) + { + boost::ignore_unused(vals); + return std::forward(arg); + } + + template + static + typename std::enable_if< + std::is_placeholder::type>::value != 0, + tuple_element::type>::value - 1, + Vals>>::type&& + extract(Arg&&, Vals&& vals) + { + return detail::get::type>::value - 1>( + std::forward(vals)); + } + + template + static + typename std::enable_if< + boost::is_placeholder::type>::value != 0, + tuple_element::type>::value - 1, + Vals>>::type&& + extract(Arg&&, Vals&& vals) + { + return detail::get::type>::value - 1>( + std::forward(vals)); + } + + template + static + void + invoke( + Handler& h, + ArgsTuple& args, + tuple<>&&, + mp11::index_sequence) + { + boost::ignore_unused(args); + h(detail::get(std::move(args))...); + } + + template< + class ArgsTuple, + class ValsTuple, + std::size_t... S> + static + void + invoke( + Handler& h, + ArgsTuple& args, + ValsTuple&& vals, + mp11::index_sequence) + { + boost::ignore_unused(args); + boost::ignore_unused(vals); + h(extract(detail::get(std::move(args)), + std::forward(vals))...); + } + +public: + using result_type = void; // asio needs this + + bind_wrapper(bind_wrapper&&) = default; + bind_wrapper(bind_wrapper const&) = default; + + template< + class DeducedHandler, + class... Args_> + explicit + bind_wrapper( + DeducedHandler&& handler, + Args_&&... args) + : h_(std::forward(handler)) + , args_(std::forward(args)...) + { + } + + template + void + operator()(Values&&... values) + { + invoke(h_, args_, + tuple( + std::forward(values)...), + mp11::index_sequence_for()); + } + + // + + template + friend + boost::asio::asio_handler_invoke_is_deprecated + asio_handler_invoke( + Function&& f, bind_wrapper* op) + { + using boost::asio::asio_handler_invoke; + return asio_handler_invoke(f, std::addressof(op->h_)); + } + + friend + bool asio_handler_is_continuation( + bind_wrapper* op) + { + using boost::asio::asio_handler_is_continuation; + return asio_handler_is_continuation( + std::addressof(op->h_)); + } + + friend + boost::asio::asio_handler_allocate_is_deprecated + asio_handler_allocate( + std::size_t size, bind_wrapper* op) + { + using boost::asio::asio_handler_allocate; + return asio_handler_allocate( + size, std::addressof(op->h_)); + } + + friend + boost::asio::asio_handler_deallocate_is_deprecated + asio_handler_deallocate( + void* p, std::size_t size, bind_wrapper* op) + { + using boost::asio::asio_handler_deallocate; + return asio_handler_deallocate( + p, size, std::addressof(op->h_)); + } +}; + +template +class bind_back_wrapper; + +template +class bind_front_wrapper; + +//------------------------------------------------------------------------------ +// +// bind_front +// +//------------------------------------------------------------------------------ + +template +class bind_front_wrapper +{ + Handler h_; + detail::tuple args_; + + template + friend struct net::associated_executor; + + template + friend struct net::associated_allocator; + + template + void + invoke( + std::false_type, + mp11::index_sequence, + Ts&&... ts) + { + h_( detail::get(std::move(args_))..., + std::forward(ts)...); + } + + template + void + invoke( + std::true_type, + mp11::index_sequence, + Ts&&... ts) + { + std::mem_fn(h_)( + detail::get(std::move(args_))..., + std::forward(ts)...); + } + +public: + using result_type = void; // asio needs this + + bind_front_wrapper(bind_front_wrapper&&) = default; + bind_front_wrapper(bind_front_wrapper const&) = default; + + template + bind_front_wrapper( + Handler_&& handler, + Args_&&... args) + : h_(std::forward(handler)) + , args_(std::forward(args)...) + { + } + + template + void operator()(Ts&&... ts) + { + invoke( + std::is_member_function_pointer{}, + mp11::index_sequence_for{}, + std::forward(ts)...); + } + + // + + template + friend + boost::asio::asio_handler_invoke_is_deprecated + asio_handler_invoke( + Function&& f, bind_front_wrapper* op) + { + using boost::asio::asio_handler_invoke; + return asio_handler_invoke(f, std::addressof(op->h_)); + } + + friend + bool asio_handler_is_continuation( + bind_front_wrapper* op) + { + using boost::asio::asio_handler_is_continuation; + return asio_handler_is_continuation( + std::addressof(op->h_)); + } + + friend + boost::asio::asio_handler_allocate_is_deprecated + asio_handler_allocate( + std::size_t size, bind_front_wrapper* op) + { + using boost::asio::asio_handler_allocate; + return asio_handler_allocate( + size, std::addressof(op->h_)); + } + + friend + boost::asio::asio_handler_deallocate_is_deprecated + asio_handler_deallocate( + void* p, std::size_t size, bind_front_wrapper* op) + { + using boost::asio::asio_handler_deallocate; + return asio_handler_deallocate( + p, size, std::addressof(op->h_)); + } +}; + +} // detail +} // beast +} // boost + +//------------------------------------------------------------------------------ + +namespace boost { +namespace asio { + +template +struct associated_executor< + beast::detail::bind_wrapper, Executor> +{ + using type = typename + associated_executor::type; + + static + type + get(beast::detail::bind_wrapper const& op, + Executor const& ex = Executor{}) noexcept + { + return associated_executor< + Handler, Executor>::get(op.h_, ex); + } +}; + +template +struct associated_executor< + beast::detail::bind_front_wrapper, Executor> +{ + using type = typename + associated_executor::type; + + static + type + get(beast::detail::bind_front_wrapper const& op, + Executor const& ex = Executor{}) noexcept + { + return associated_executor< + Handler, Executor>::get(op.h_, ex); + } +}; + +// + +template +struct associated_allocator< + beast::detail::bind_wrapper, Allocator> +{ + using type = typename + associated_allocator::type; + + static + type + get(beast::detail::bind_wrapper const& op, + Allocator const& alloc = Allocator{}) noexcept + { + return associated_allocator< + Handler, Allocator>::get(op.h_, alloc); + } +}; + +template +struct associated_allocator< + beast::detail::bind_front_wrapper, Allocator> +{ + using type = typename + associated_allocator::type; + + static + type + get(beast::detail::bind_front_wrapper const& op, + Allocator const& alloc = Allocator{}) noexcept + { + return associated_allocator< + Handler, Allocator>::get(op.h_, alloc); + } +}; + +} // asio +} // boost + +//------------------------------------------------------------------------------ + +namespace std { + +// VFALCO Using std::bind on a completion handler will +// cause undefined behavior later, because the executor +// associated with the handler is not propagated to the +// wrapper returned by std::bind; these overloads are +// deleted to prevent mistakes. If this creates a problem +// please contact me. + +template +void +bind(boost::beast::detail::bind_wrapper< + Handler, Args...>, ...) = delete; + +template +void +bind(boost::beast::detail::bind_front_wrapper< + Handler, Args...>, ...) = delete; + +} // std + +//------------------------------------------------------------------------------ + +#endif diff --git a/plugins/trace_api_plugin/abi_data_handler.cpp b/plugins/trace_api_plugin/abi_data_handler.cpp index 06462d7e5a4..28e6c1228fb 100644 --- a/plugins/trace_api_plugin/abi_data_handler.cpp +++ b/plugins/trace_api_plugin/abi_data_handler.cpp @@ -27,12 +27,16 @@ namespace eosio::trace_api { }; return std::visit([&](auto &&action) -> std::tuple> { using T = std::decay_t; - if constexpr (std::is_same_v) { - return {serializer_p->binary_to_variant(type_name, action.data, abi_yield), {}}; - } else { - return {serializer_p->binary_to_variant(type_name, action.data, abi_yield), - {serializer_p->binary_to_variant(type_name, action.return_value, abi_yield)}}; + std::optional ret_data; + auto params = serializer_p->binary_to_variant(type_name, action.data, abi_yield); + if constexpr (std::is_same_v) { + // if there is no return data, an exception will be thrown, so catch it here + try { + ret_data = serializer_p->binary_to_variant(type_name, action.return_value, abi_yield); + } + catch(...) { } } + return {params, ret_data}; }, action); } catch (...) { except_handler(MAKE_EXCEPTION_WITH_CONTEXT(std::current_exception())); From c685291aec8c9a34a0a172f58d41050ca0875545 Mon Sep 17 00:00:00 2001 From: Patrick Raphael Date: Tue, 22 Jun 2021 21:04:53 -0400 Subject: [PATCH 2/4] remove mistanely added bind_handler --- plugins/http_plugin/bind_handler.hpp | 132 --------------------------- 1 file changed, 132 deletions(-) delete mode 100644 plugins/http_plugin/bind_handler.hpp diff --git a/plugins/http_plugin/bind_handler.hpp b/plugins/http_plugin/bind_handler.hpp deleted file mode 100644 index cfa6a74bf54..00000000000 --- a/plugins/http_plugin/bind_handler.hpp +++ /dev/null @@ -1,132 +0,0 @@ -// -// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/boostorg/beast -// - -#ifndef BOOST_BEAST_BIND_HANDLER_HPP -#define BOOST_BEAST_BIND_HANDLER_HPP - -#include -#include -#include -#include - -namespace boost { -namespace beast { - -/** Bind parameters to a completion handler, creating a new handler. - - This function creates a new handler which, when invoked, calls - the original handler with the list of bound arguments. Any - parameters passed in the invocation will be substituted for - placeholders present in the list of bound arguments. Parameters - which are not matched to placeholders are silently discarded. - - The passed handler and arguments are forwarded into the returned - handler, whose associated allocator and associated executor will - will be the same as those of the original handler. - - @par Example - - This function posts the invocation of the specified completion - handler with bound arguments: - - @code - template - void - signal_aborted (AsyncReadStream& stream, ReadHandler&& handler) - { - net::post( - stream.get_executor(), - bind_handler (std::forward (handler), - net::error::operation_aborted, 0)); - } - @endcode - - @param handler The handler to wrap. - The implementation takes ownership of the handler by performing a decay-copy. - - @param args A list of arguments to bind to the handler. - The arguments are forwarded into the returned object. These - arguments may include placeholders, which will operate in - a fashion identical to a call to `std::bind`. -*/ -template -#if BOOST_BEAST_DOXYGEN -__implementation_defined__ -#else -detail::bind_wrapper< - typename std::decay::type, - typename std::decay::type...> -#endif -bind_handler(Handler&& handler, Args&&... args) -{ - return detail::bind_wrapper< - typename std::decay::type, - typename std::decay::type...>( - std::forward(handler), - std::forward(args)...); -} - -/** Bind parameters to a completion handler, creating a new handler. - - This function creates a new handler which, when invoked, calls - the original handler with the list of bound arguments. Any - parameters passed in the invocation will be forwarded in - the parameter list after the bound arguments. - - The passed handler and arguments are forwarded into the returned - handler, whose associated allocator and associated executor will - will be the same as those of the original handler. - - @par Example - - This function posts the invocation of the specified completion - handler with bound arguments: - - @code - template - void - signal_eof (AsyncReadStream& stream, ReadHandler&& handler) - { - net::post( - stream.get_executor(), - bind_front_handler (std::forward (handler), - net::error::eof, 0)); - } - @endcode - - @param handler The handler to wrap. - The implementation takes ownership of the handler by performing a decay-copy. - - @param args A list of arguments to bind to the handler. - The arguments are forwarded into the returned object. -*/ -template -#if BOOST_BEAST_DOXYGEN -__implementation_defined__ -#else -auto -#endif -bind_front_handler( - Handler&& handler, - Args&&... args) -> - detail::bind_front_wrapper< - typename std::decay::type, - typename std::decay::type...> -{ - return detail::bind_front_wrapper< - typename std::decay::type, - typename std::decay::type...>( - std::forward(handler), - std::forward(args)...); -} - -} // beast -} // boost - -#endif From 9853626166503b77562ceda73fe6a3ad363e9daa Mon Sep 17 00:00:00 2001 From: Patrick Raphael Date: Tue, 22 Jun 2021 21:55:04 -0400 Subject: [PATCH 3/4] test for existnce of 'params' field in trace_plugin_test --- tests/trace_plugin_test.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/trace_plugin_test.py b/tests/trace_plugin_test.py index 9b0e7fd2318..119717fa51c 100755 --- a/tests/trace_plugin_test.py +++ b/tests/trace_plugin_test.py @@ -2,6 +2,7 @@ import json import time import unittest +import os from testUtils import Utils from Cluster import Cluster @@ -29,7 +30,8 @@ def cleanEnv(self, shouldCleanup: bool) : # start keosd and nodeos def startEnv(self) : account_names = ["alice", "bob", "charlie"] - traceNodeosArgs = " --plugin eosio::trace_api_plugin --trace-no-abis --trace-dir=." + abs_path = os.path.abspath(os.getcwd() + '/../unittests/contracts/eosio.token/eosio.token.abi') + traceNodeosArgs = " --plugin eosio::trace_api_plugin --trace-rpc-abi eosio.token=" + abs_path + " --trace-dir=." self.cluster.launch(totalNodes=1, extraNodeosArgs=traceNodeosArgs) self.walletMgr.launch() testWalletName="testwallet" @@ -90,6 +92,15 @@ def test_TraceApi(self) : self.assertIn("id", trx) if (trx["id"] == transId) : isTrxInBlockFromTraceApi = True + self.assertIn('actions', trx) + actions = trx['actions'] + for act in actions: + self.assertIn('params', act) + prms = act['params'] + self.assertIn('from', prms) + self.assertIn('to', prms) + self.assertIn('quantity', prms) + self.assertIn('memo', prms) break self.assertTrue(isTrxInBlockFromTraceApi) From 1fefb152af50a6426bf9edc64b0acfe5950c0bfc Mon Sep 17 00:00:00 2001 From: Patrick Raphael Date: Tue, 22 Jun 2021 22:03:57 -0400 Subject: [PATCH 4/4] remove mistakenly added bind_Handler_detail.cpp --- plugins/http_plugin/bind_handler_detail.hpp | 416 -------------------- 1 file changed, 416 deletions(-) delete mode 100644 plugins/http_plugin/bind_handler_detail.hpp diff --git a/plugins/http_plugin/bind_handler_detail.hpp b/plugins/http_plugin/bind_handler_detail.hpp deleted file mode 100644 index 07db8d4b95b..00000000000 --- a/plugins/http_plugin/bind_handler_detail.hpp +++ /dev/null @@ -1,416 +0,0 @@ -// -// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/boostorg/beast -// - -#ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP -#define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace beast { -namespace detail { - -//------------------------------------------------------------------------------ -// -// bind_handler -// -//------------------------------------------------------------------------------ - -template -class bind_wrapper -{ - using args_type = detail::tuple; - - Handler h_; - args_type args_; - - template - friend struct net::associated_executor; - - template - friend struct net::associated_allocator; - - template - static - typename std::enable_if< - std::is_placeholder::type>::value == 0 && - boost::is_placeholder::type>::value == 0, - Arg&&>::type - extract(Arg&& arg, Vals&& vals) - { - boost::ignore_unused(vals); - return std::forward(arg); - } - - template - static - typename std::enable_if< - std::is_placeholder::type>::value != 0, - tuple_element::type>::value - 1, - Vals>>::type&& - extract(Arg&&, Vals&& vals) - { - return detail::get::type>::value - 1>( - std::forward(vals)); - } - - template - static - typename std::enable_if< - boost::is_placeholder::type>::value != 0, - tuple_element::type>::value - 1, - Vals>>::type&& - extract(Arg&&, Vals&& vals) - { - return detail::get::type>::value - 1>( - std::forward(vals)); - } - - template - static - void - invoke( - Handler& h, - ArgsTuple& args, - tuple<>&&, - mp11::index_sequence) - { - boost::ignore_unused(args); - h(detail::get(std::move(args))...); - } - - template< - class ArgsTuple, - class ValsTuple, - std::size_t... S> - static - void - invoke( - Handler& h, - ArgsTuple& args, - ValsTuple&& vals, - mp11::index_sequence) - { - boost::ignore_unused(args); - boost::ignore_unused(vals); - h(extract(detail::get(std::move(args)), - std::forward(vals))...); - } - -public: - using result_type = void; // asio needs this - - bind_wrapper(bind_wrapper&&) = default; - bind_wrapper(bind_wrapper const&) = default; - - template< - class DeducedHandler, - class... Args_> - explicit - bind_wrapper( - DeducedHandler&& handler, - Args_&&... args) - : h_(std::forward(handler)) - , args_(std::forward(args)...) - { - } - - template - void - operator()(Values&&... values) - { - invoke(h_, args_, - tuple( - std::forward(values)...), - mp11::index_sequence_for()); - } - - // - - template - friend - boost::asio::asio_handler_invoke_is_deprecated - asio_handler_invoke( - Function&& f, bind_wrapper* op) - { - using boost::asio::asio_handler_invoke; - return asio_handler_invoke(f, std::addressof(op->h_)); - } - - friend - bool asio_handler_is_continuation( - bind_wrapper* op) - { - using boost::asio::asio_handler_is_continuation; - return asio_handler_is_continuation( - std::addressof(op->h_)); - } - - friend - boost::asio::asio_handler_allocate_is_deprecated - asio_handler_allocate( - std::size_t size, bind_wrapper* op) - { - using boost::asio::asio_handler_allocate; - return asio_handler_allocate( - size, std::addressof(op->h_)); - } - - friend - boost::asio::asio_handler_deallocate_is_deprecated - asio_handler_deallocate( - void* p, std::size_t size, bind_wrapper* op) - { - using boost::asio::asio_handler_deallocate; - return asio_handler_deallocate( - p, size, std::addressof(op->h_)); - } -}; - -template -class bind_back_wrapper; - -template -class bind_front_wrapper; - -//------------------------------------------------------------------------------ -// -// bind_front -// -//------------------------------------------------------------------------------ - -template -class bind_front_wrapper -{ - Handler h_; - detail::tuple args_; - - template - friend struct net::associated_executor; - - template - friend struct net::associated_allocator; - - template - void - invoke( - std::false_type, - mp11::index_sequence, - Ts&&... ts) - { - h_( detail::get(std::move(args_))..., - std::forward(ts)...); - } - - template - void - invoke( - std::true_type, - mp11::index_sequence, - Ts&&... ts) - { - std::mem_fn(h_)( - detail::get(std::move(args_))..., - std::forward(ts)...); - } - -public: - using result_type = void; // asio needs this - - bind_front_wrapper(bind_front_wrapper&&) = default; - bind_front_wrapper(bind_front_wrapper const&) = default; - - template - bind_front_wrapper( - Handler_&& handler, - Args_&&... args) - : h_(std::forward(handler)) - , args_(std::forward(args)...) - { - } - - template - void operator()(Ts&&... ts) - { - invoke( - std::is_member_function_pointer{}, - mp11::index_sequence_for{}, - std::forward(ts)...); - } - - // - - template - friend - boost::asio::asio_handler_invoke_is_deprecated - asio_handler_invoke( - Function&& f, bind_front_wrapper* op) - { - using boost::asio::asio_handler_invoke; - return asio_handler_invoke(f, std::addressof(op->h_)); - } - - friend - bool asio_handler_is_continuation( - bind_front_wrapper* op) - { - using boost::asio::asio_handler_is_continuation; - return asio_handler_is_continuation( - std::addressof(op->h_)); - } - - friend - boost::asio::asio_handler_allocate_is_deprecated - asio_handler_allocate( - std::size_t size, bind_front_wrapper* op) - { - using boost::asio::asio_handler_allocate; - return asio_handler_allocate( - size, std::addressof(op->h_)); - } - - friend - boost::asio::asio_handler_deallocate_is_deprecated - asio_handler_deallocate( - void* p, std::size_t size, bind_front_wrapper* op) - { - using boost::asio::asio_handler_deallocate; - return asio_handler_deallocate( - p, size, std::addressof(op->h_)); - } -}; - -} // detail -} // beast -} // boost - -//------------------------------------------------------------------------------ - -namespace boost { -namespace asio { - -template -struct associated_executor< - beast::detail::bind_wrapper, Executor> -{ - using type = typename - associated_executor::type; - - static - type - get(beast::detail::bind_wrapper const& op, - Executor const& ex = Executor{}) noexcept - { - return associated_executor< - Handler, Executor>::get(op.h_, ex); - } -}; - -template -struct associated_executor< - beast::detail::bind_front_wrapper, Executor> -{ - using type = typename - associated_executor::type; - - static - type - get(beast::detail::bind_front_wrapper const& op, - Executor const& ex = Executor{}) noexcept - { - return associated_executor< - Handler, Executor>::get(op.h_, ex); - } -}; - -// - -template -struct associated_allocator< - beast::detail::bind_wrapper, Allocator> -{ - using type = typename - associated_allocator::type; - - static - type - get(beast::detail::bind_wrapper const& op, - Allocator const& alloc = Allocator{}) noexcept - { - return associated_allocator< - Handler, Allocator>::get(op.h_, alloc); - } -}; - -template -struct associated_allocator< - beast::detail::bind_front_wrapper, Allocator> -{ - using type = typename - associated_allocator::type; - - static - type - get(beast::detail::bind_front_wrapper const& op, - Allocator const& alloc = Allocator{}) noexcept - { - return associated_allocator< - Handler, Allocator>::get(op.h_, alloc); - } -}; - -} // asio -} // boost - -//------------------------------------------------------------------------------ - -namespace std { - -// VFALCO Using std::bind on a completion handler will -// cause undefined behavior later, because the executor -// associated with the handler is not propagated to the -// wrapper returned by std::bind; these overloads are -// deleted to prevent mistakes. If this creates a problem -// please contact me. - -template -void -bind(boost::beast::detail::bind_wrapper< - Handler, Args...>, ...) = delete; - -template -void -bind(boost::beast::detail::bind_front_wrapper< - Handler, Args...>, ...) = delete; - -} // std - -//------------------------------------------------------------------------------ - -#endif