From 786792f4f0bb9652c9d92cbf95ccb4d84667a25c Mon Sep 17 00:00:00 2001 From: Denis Blank Date: Mon, 26 Feb 2018 05:04:38 +0100 Subject: [PATCH] Add cti::promisify with an initial boost asio helper --- examples/example-asio/example-asio.cpp | 31 ++---- include/continuable/continuable-promisify.hpp | 83 ++++++++++++++++ include/continuable/continuable.hpp | 1 + include/continuable/detail/promisify.hpp | 95 +++++++++++++++++++ test/playground/CMakeLists.txt | 2 + test/playground/comp.cpp | 29 +----- 6 files changed, 189 insertions(+), 52 deletions(-) create mode 100644 include/continuable/continuable-promisify.hpp create mode 100644 include/continuable/detail/promisify.hpp diff --git a/examples/example-asio/example-asio.cpp b/examples/example-asio/example-asio.cpp index 7973c5e..3564b0c 100644 --- a/examples/example-asio/example-asio.cpp +++ b/examples/example-asio/example-asio.cpp @@ -59,29 +59,12 @@ struct functional_io_service : asio::io_service { }); } - template - auto async_resolve(Protocol&& protocol, std::string host, - std::string service) { - using asio::ip::udp; - - return cti::make_continuable([ - this, protocol = std::forward(protocol), host = std::move(host), - service = std::move(service) - ](auto&& promise) mutable { - resolver_.async_resolve( - host, service, - [promise = std::forward(promise)]( - std::error_code const& error, - udp::resolver::iterator iterator) mutable { - - if (error) { - promise.set_exception( - std::error_condition(error.value(), error.category())); - } else { - promise.set_value(std::move(iterator)); - } - }); - }); + auto async_resolve(std::string host, std::string service) { + return cti::promisify::from_asio( + [&](auto&&... args) { + resolver_.async_resolve(std::forward(args)...); + }, + std::move(host), std::move(service)); } }; @@ -90,7 +73,7 @@ int main(int, char**) { functional_io_service service; - service.async_resolve(udp::v4(), "127.0.0.1", "daytime") + service.async_resolve("127.0.0.1", "daytime") .then([](udp::resolver::iterator iterator) { // ... return *iterator; diff --git a/include/continuable/continuable-promisify.hpp b/include/continuable/continuable-promisify.hpp new file mode 100644 index 0000000..050e238 --- /dev/null +++ b/include/continuable/continuable-promisify.hpp @@ -0,0 +1,83 @@ + +/* + + /~` _ _ _|_. _ _ |_ | _ + \_,(_)| | | || ||_|(_||_)|(/_ + + https://github.com/Naios/continuable + v3.0.0 + + Copyright(c) 2015 - 2018 Denis Blank + + 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 CONTINUABLE_PROMISIFY_HPP_INCLUDED +#define CONTINUABLE_PROMISIFY_HPP_INCLUDED + +#include +#include + +#include + +namespace cti { +/// Helper class for converting callback taking callable types into a +/// a continuable. Various styles are supported. +/// - `from_asio`: Converts callback taking callable types into continuables +/// which pass an error code as first parameter and the rest of +/// the result afterwards. +/// +/// \tparam Result The result of the converted continuable, this should align +/// with the arguments that are passed to the callback. +template +class promisify { + using helper = detail::convert::promisify_helper; + +public: + /// Converts callback taking callable types into a continuable. + /// This applies to calls which pass an error code as first parameter + /// and the rest of the asynchronous result afterwards. + /// + /// See an example of how to promisify boost asio's async_resolve below: + /// ```cpp + /// auto async_resolve(std::string host, std::string service) { + /// return cti::promisify::from_asio( + /// [&](auto&&... args) { + /// resolver_.async_resolve(std::forward(args)...); + /// }, + /// std::move(host), std::move(service)); + /// } + /// ``` + /// + /// If the error code which is passed as first parameter is set there are + /// two behaviours depending whether exceptions are enabled: + /// - If exceptions are enabled the error type is passed via + /// an exception_ptr to the failure handler. + /// - If exceptions are disabled the error type is copnverted to an + /// `std::error_conditon` and passed down to the error handler. + /// + template + static auto from_asio(Callable&& callable, Args&&... args) { + return helper::template from( + std::forward(callable), std::forward(args)...); + } +}; +} // namespace cti + +#endif // CONTINUABLE_PROMISIFY_HPP_INCLUDED diff --git a/include/continuable/continuable.hpp b/include/continuable/continuable.hpp index 4071151..0dd1541 100644 --- a/include/continuable/continuable.hpp +++ b/include/continuable/continuable.hpp @@ -48,6 +48,7 @@ namespace cti {} #include #include #include +#include #include #include #include diff --git a/include/continuable/detail/promisify.hpp b/include/continuable/detail/promisify.hpp new file mode 100644 index 0000000..88ef538 --- /dev/null +++ b/include/continuable/detail/promisify.hpp @@ -0,0 +1,95 @@ + +/* + + /~` _ _ _|_. _ _ |_ | _ + \_,(_)| | | || ||_|(_||_)|(/_ + + https://github.com/Naios/continuable + v3.0.0 + + Copyright(c) 2015 - 2018 Denis Blank + + 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 CONTINUABLE_DETAIL_PROMISIFY_HPP_INCLUDED +#define CONTINUABLE_DETAIL_PROMISIFY_HPP_INCLUDED + +#include + +#if defined(CONTINUABLE_HAS_EXCEPTIONS) +#include +#endif // CONTINUABLE_HAS_EXCEPTIONS + +#include +#include +#include + +namespace cti { +namespace detail { +namespace convert { +/// A helper class for promisifying asio style callback taking functions +/// into a continuable. +template +struct promisify_asio { + P promise; + + template + void operator()(E&& error, T&&... result) { + if (error) { +#if defined(CONTINUABLE_HAS_EXCEPTIONS) + promise.set_exception(std::make_exception_ptr(std::forward(error))); +#else + promise.set_exception( + std::error_condition(error.value(), error.category())); +#endif // CONTINUABLE_HAS_EXCEPTIONS + + } else { + promise.set_value(std::forward(result)...); + } + } +}; + +template +struct promisify_helper { + template