Introduce the continuable primitive header which supplies tags

* Adapts the new naming scheme from the "Unified Futures" proposal
* Provides new tags for the future inplace resolution
This commit is contained in:
Denis Blank 2018-11-18 19:00:38 +01:00
parent 2ff7bb9b8d
commit 057fb37123
20 changed files with 263 additions and 170 deletions

View File

@ -50,7 +50,7 @@ inline auto error_code_remapper() {
#if defined(CONTINUABLE_HAS_EXCEPTIONS) #if defined(CONTINUABLE_HAS_EXCEPTIONS)
promise.set_exception(std::make_exception_ptr(e)); promise.set_exception(std::make_exception_ptr(e));
#else #else
promise.set_exception(cti::error_type(e.value(), e.category())); promise.set_exception(cti::exception_t(e.value(), e.category()));
#endif #endif
} else { } else {
promise.set_value(std::forward<decltype(args)>(args)...); promise.set_value(std::forward<decltype(args)>(args)...);
@ -108,7 +108,7 @@ int main(int, char**) {
// auto socket = std::make_shared<udp::socket>(service); // auto socket = std::make_shared<udp::socket>(service);
// socket->async_send_to() // socket->async_send_to()
}) })
.fail([](cti::error_type /*error*/) { .fail([](cti::exception_t /*error*/) {
// ... // ...
}); });

View File

@ -35,6 +35,7 @@
#include <cstddef> #include <cstddef>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/connection/connection-all.hpp> #include <continuable/detail/connection/connection-all.hpp>
#include <continuable/detail/connection/connection-any.hpp> #include <continuable/detail/connection/connection-any.hpp>
#include <continuable/detail/connection/connection-seq.hpp> #include <continuable/detail/connection/connection-seq.hpp>
@ -55,41 +56,6 @@ namespace cti {
/// provides classes and functions to create continuable_base objects. /// provides classes and functions to create continuable_base objects.
/// \{ /// \{
/// Represents a tag which can be placed first in a signature
/// in order to overload callables with the asynchronous result
/// as well as an error.
///
/// See the example below:
/// ```cpp
/// struct my_callable {
/// void operator() (std::string result) {
/// // ...
/// }
/// void operator() (cti::dispatch_error_tag, cti::error_type) {
/// // ...
/// }
/// };
///
/// // Will receive errors and results
/// continuable.next(my_callable{});
/// ```
///
/// \note see continuable::next for details.
///
/// \since 2.0.0
using dispatch_error_tag = detail::types::dispatch_error_tag;
/// Represents the type that is used as error type
///
/// By default this type deduces to `std::exception_ptr`.
/// If `CONTINUABLE_WITH_NO_EXCEPTIONS` is defined the type
/// will be a `std::error_condition`.
/// A custom error type may be set through
/// defining `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE`.
///
/// \since 2.0.0
using error_type = detail::types::error_type;
/// Deduces to a true_type if the given type is a continuable_base. /// Deduces to a true_type if the given type is a continuable_base.
/// ///
/// \since 3.0.0 /// \since 3.0.0
@ -371,8 +337,10 @@ public:
template <typename OData, typename OAnnotation> template <typename OData, typename OAnnotation>
auto fail(continuable_base<OData, OAnnotation>&& continuation) && { auto fail(continuable_base<OData, OAnnotation>&& continuation) && {
continuation.freeze(); continuation.freeze();
return std::move(*this).fail([continuation = std::move(continuation)]( return std::move(*this).fail(
error_type) mutable { std::move(continuation).done(); }); [continuation = std::move(continuation)](exception_t) mutable {
std::move(continuation).done();
});
} }
/// A method which allows to use an overloaded callable for the error /// A method which allows to use an overloaded callable for the error
@ -386,7 +354,7 @@ public:
/// void operator() (std::string result) { /// void operator() (std::string result) {
/// // ... /// // ...
/// } /// }
/// void operator() (cti::dispatch_error_tag, cti::error_type) { /// void operator() (cti::exception_arg_t, cti::exception_t) {
/// // ... /// // ...
/// } /// }
/// ///
@ -658,7 +626,7 @@ public:
/// if (auto&& result = co_await http_request("github.com")) { /// if (auto&& result = co_await http_request("github.com")) {
/// auto value = *result; /// auto value = *result;
/// } else { /// } else {
/// cti::error_type error = result.get_exception(); /// cti::exception_t error = result.get_exception();
/// } /// }
/// ///
/// auto result = co_await http_request("github.com"); /// auto result = co_await http_request("github.com");

View File

@ -0,0 +1,128 @@
/*
/~` _ _ _|_. _ _ |_ | _
\_,(_)| | | || ||_|(_||_)|(/_
https://github.com/Naios/continuable
v3.0.0
Copyright(c) 2015 - 2018 Denis Blank <denis.blank at outlook dot com>
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_PRIMITIVES_HPP_INCLUDED
#define CONTINUABLE_PRIMITIVES_HPP_INCLUDED
#include <continuable/detail/core/types.hpp>
namespace cti {
/// \defgroup Primitives Primitives
/// provides basic tag types for creating a customized callbacks
/// and continuations.
/// For the callback and the continuation `Args...` represents the
/// asynchronous results:
/// ```cpp
/// template<typename... Args>
/// struct continuation {
/// void operator() (callback<Args...>);
/// bool operator() (cti::is_ready_arg_t) const;
/// std::tuple<Args...> operator() (cti::get_arg_t);
/// };
/// template<typename T>
/// struct continuation<T> {
/// template<typename Callback>
/// void operator() (callback<T>);
/// bool operator() (cti::is_ready_arg_t) const;
/// T operator() (cti::get_arg_t);
/// };
/// template<>
/// struct continuation<void> {
/// void operator() (callback<>);
/// bool operator() (cti::is_ready_arg_t) const;
/// void operator() (cti::get_arg_t);
/// };
/// ```
/// ```cpp
/// template<typename... Args>
/// struct callback {
/// void operator() (Args...);
/// void operator() (cti::exception_arg_t, cti::exception_t);
/// };
/// ```
/// \{
/// Represents the tag type that is used to query the continuation
/// for whether it resolves the callback instantly with its arguments
/// without having side effects.
///
/// \since 4.0.0
struct is_ready_arg_t {};
/// Represents the tag type that is used to query the continuation
/// for its arguments when resolves the callback instantly
/// without having side effects.
/// It's required that the query of is_ready_arg_t returns true.
///
/// \since 4.0.0
struct get_arg_t {};
/// Represents the tag type that is used to disambiguate the
/// callback operator() in order to take the exception asynchronous chain.
///
/// \note see continuable::next for details.
///
/// \since 4.0.0
struct exception_arg_t {};
/// \copydoc exception_arg_t
///
/// \deprecated The exception_arg_t was deprecated in order to move closer
/// to the types specified in the "A Unified Future" proposal
/// especially regarding naming types similar.
///
[[deprecated("The dispatch_error_tag was replaced by exception_arg_t and will "
"be removed in a later major version!")]] //
typedef exception_arg_t dispatch_error_tag;
/// Represents the type that is used as exception type
///
/// By default this type deduces to `std::exception_ptr`.
/// If `CONTINUABLE_WITH_NO_EXCEPTIONS` is defined the type
/// will be a `std::error_condition`.
/// A custom error type may be set through
/// defining `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE`.
///
/// \since 4.0.0
using exception_t = detail::types::exception_t;
/// \copydoc exception_t
///
/// \deprecated The exception_t was deprecated in order to move closer
/// to the types specified in the "A Unified Future" proposal
/// especially regarding naming types similar.
///
[[deprecated("The error_type was replaced by exception_t and will "
"be removed in a later major version!")]] //
typedef exception_t error_type;
/// \}
} // namespace cti
#endif // CONTINUABLE_PRIMITIVES_HPP_INCLUDED

View File

@ -33,6 +33,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/core/hints.hpp> #include <continuable/detail/core/hints.hpp>
#include <continuable/detail/core/types.hpp> #include <continuable/detail/core/types.hpp>
#include <continuable/detail/utility/util.hpp> #include <continuable/detail/utility/util.hpp>
@ -50,7 +51,7 @@ namespace cti {
/// ///
/// If we want to resolve the promise_base trough the call operator, /// If we want to resolve the promise_base trough the call operator,
/// and we want to resolve it through an exception, we must call it with a /// and we want to resolve it through an exception, we must call it with a
/// dispatch_error_tag as first and the exception as second argument. /// exception_arg_t as first and the exception as second argument.
/// Additionally the promise is resolveable only through its call /// Additionally the promise is resolveable only through its call
/// operator when invoked as an r-value. /// operator when invoked as an r-value.
/// ///
@ -100,8 +101,8 @@ public:
/// \throws This method never throws an exception. /// \throws This method never throws an exception.
/// ///
/// \since 2.0.0 /// \since 2.0.0
void operator()(detail::types::dispatch_error_tag tag, void operator()(exception_arg_t tag,
detail::types::error_type exception) && exception_t exception) &&
noexcept { noexcept {
std::move(data_)(tag, std::move(exception)); std::move(data_)(tag, std::move(exception));
} }
@ -120,8 +121,8 @@ public:
/// \throws This method never throws an exception. /// \throws This method never throws an exception.
/// ///
/// \since 2.0.0 /// \since 2.0.0
void set_exception(detail::types::error_type exception) noexcept { void set_exception(exception_t exception) noexcept {
std::move(data_)(detail::types::dispatch_error_tag{}, std::move(exception)); std::move(data_)(exception_arg_t{}, std::move(exception));
} }
}; };
/// \} /// \}

View File

@ -32,6 +32,7 @@
#define CONTINUABLE_TRAIT_HPP_INCLUDED #define CONTINUABLE_TRAIT_HPP_INCLUDED
#include <cstddef> #include <cstddef>
#include <continuable/continuable-primitives.hpp>
#include <continuable/continuable-base.hpp> #include <continuable/continuable-base.hpp>
#include <continuable/continuable-promise-base.hpp> #include <continuable/continuable-promise-base.hpp>
#include <continuable/detail/core/hints.hpp> #include <continuable/detail/core/hints.hpp>
@ -60,8 +61,8 @@ template <template <std::size_t, typename...> class CallbackWrapper,
class continuable_trait { class continuable_trait {
using callback = CallbackWrapper<0U, void(Args...)&&, using callback = CallbackWrapper<0U, void(Args...)&&,
void(detail::types::dispatch_error_tag, void(exception_arg_t,
detail::types::error_type) &&>; exception_t) &&>;
public: public:
/// The promise type which is used to resolve continuations /// The promise type which is used to resolve continuations

View File

@ -48,6 +48,7 @@ namespace cti {}
#include <continuable/continuable-base.hpp> #include <continuable/continuable-base.hpp>
#include <continuable/continuable-connections.hpp> #include <continuable/continuable-connections.hpp>
#include <continuable/continuable-coroutine.hpp> #include <continuable/continuable-coroutine.hpp>
#include <continuable/continuable-primitives.hpp>
#include <continuable/continuable-promise-base.hpp> #include <continuable/continuable-promise-base.hpp>
#include <continuable/continuable-promisify.hpp> #include <continuable/continuable-promisify.hpp>
#include <continuable/continuable-trait.hpp> #include <continuable/continuable-trait.hpp>

View File

@ -37,6 +37,7 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/connection/connection-aggregated.hpp> #include <continuable/detail/connection/connection-aggregated.hpp>
#include <continuable/detail/connection/connection.hpp> #include <continuable/detail/connection/connection.hpp>
#include <continuable/detail/core/base.hpp> #include <continuable/detail/core/base.hpp>
@ -98,7 +99,7 @@ class result_submitter
} }
template <typename... PartialArgs> template <typename... PartialArgs>
void operator()(types::dispatch_error_tag tag, types::error_type error) && { void operator()(exception_arg_t tag, exception_t error) && {
// We never complete the connection, but we forward the first error // We never complete the connection, but we forward the first error
// which was raised. // which was raised.
std::call_once(me->flag_, std::move(me->callback_), tag, std::call_once(me->flag_, std::move(me->callback_), tag,

View File

@ -37,6 +37,7 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/continuable-primitives.hpp>
#include <continuable/continuable-promise-base.hpp> #include <continuable/continuable-promise-base.hpp>
#include <continuable/continuable-traverse.hpp> #include <continuable/continuable-traverse.hpp>
#include <continuable/detail/core/base.hpp> #include <continuable/detail/core/base.hpp>

View File

@ -36,6 +36,7 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/continuable-primitives.hpp>
#include <continuable/continuable-traverse-async.hpp> #include <continuable/continuable-traverse-async.hpp>
#include <continuable/detail/connection/connection-aggregated.hpp> #include <continuable/detail/connection/connection-aggregated.hpp>
#include <continuable/detail/core/base.hpp> #include <continuable/detail/core/base.hpp>
@ -55,16 +56,16 @@ auto sequential_connect(Left&& left, Right&& right) {
left.freeze(right.is_frozen()); left.freeze(right.is_frozen());
right.freeze(); right.freeze();
return std::forward<Left>(left).then([right = std::forward<Right>(right)]( return std::forward<Left>(left).then(
auto&&... args) mutable { [right = std::forward<Right>(right)](auto&&... args) mutable {
return std::move(right).then([previous = std::make_tuple( return std::move(right).then(
std::forward<decltype(args)>(args)...)]( [previous = std::make_tuple(std::forward<decltype(args)>(args)...)](
auto&&... args) mutable { auto&&... args) mutable {
return std::tuple_cat( return std::tuple_cat(
std::move(previous), std::move(previous),
std::make_tuple(std::forward<decltype(args)>(args)...)); std::make_tuple(std::forward<decltype(args)>(args)...));
}); });
}); });
} }
template <typename Callback, typename Box> template <typename Callback, typename Box>
@ -100,18 +101,17 @@ public:
template <typename Box, typename N> template <typename Box, typename N>
void operator()(async_traverse_detach_tag, Box&& box, N&& next) { void operator()(async_traverse_detach_tag, Box&& box, N&& next) {
box.fetch() box.fetch()
.then([ box = std::addressof(box), .then([box = std::addressof(box),
next = std::forward<N>(next) ](auto&&... args) mutable { next = std::forward<N>(next)](auto&&... args) mutable {
// Assign the result to the target // Assign the result to the target
box->assign(std::forward<decltype(args)>(args)...); box->assign(std::forward<decltype(args)>(args)...);
// Continue the asynchronous sequential traversal // Continue the asynchronous sequential traversal
next(); next();
}) })
.fail([me = this->shared_from_this()](types::error_type exception) { .fail([me = this->shared_from_this()](exception_t exception) {
// Abort the traversal when an error occurred // Abort the traversal when an error occurred
std::move(me->data_.callback)(types::dispatch_error_tag{}, std::move(me->data_.callback)(exception_arg_t{},
std::move(exception)); std::move(exception));
}) })
.done(); .done();
@ -144,7 +144,6 @@ struct connection_finalizer<connection_strategy_seq_tag> {
return base::attorney::create( return base::attorney::create(
[result = std::move(result)](auto&& callback) mutable { [result = std::move(result)](auto&& callback) mutable {
// The data from which the visitor is constructed in-place // The data from which the visitor is constructed in-place
using data_t = using data_t =
seq::sequential_dispatch_data<std::decay_t<decltype(callback)>, seq::sequential_dispatch_data<std::decay_t<decltype(callback)>,

View File

@ -34,6 +34,7 @@
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/core/hints.hpp> #include <continuable/detail/core/hints.hpp>
#include <continuable/detail/core/types.hpp> #include <continuable/detail/core/types.hpp>
#include <continuable/detail/features.hpp> #include <continuable/detail/features.hpp>
@ -140,7 +141,7 @@ public:
} \ } \
catch (...) { \ catch (...) { \
std::forward<decltype(next_callback)>(next_callback)( \ std::forward<decltype(next_callback)>(next_callback)( \
types::dispatch_error_tag{}, std::current_exception()); \ exception_arg_t{}, std::current_exception()); \
} }
#else // CONTINUABLE_HAS_EXCEPTIONS #else // CONTINUABLE_HAS_EXCEPTIONS
@ -274,10 +275,8 @@ void packed_dispatch(Executor&& executor, Invoker&& invoker, Args&&... args) {
// Create a worker object which when invoked calls the callback with the // Create a worker object which when invoked calls the callback with the
// the returned arguments. // the returned arguments.
auto work = [ auto work = [invoker = std::forward<Invoker>(invoker),
invoker = std::forward<Invoker>(invoker), args = std::make_tuple(std::forward<Args>(args)...)]() mutable {
args = std::make_tuple(std::forward<Args>(args)...)
]() mutable {
traits::unpack( traits::unpack(
[&](auto&&... captured_args) { [&](auto&&... captured_args) {
// Just use the packed dispatch method which dispatches the work on // Just use the packed dispatch method which dispatches the work on
@ -345,7 +344,7 @@ struct result_handler_base<handle_results::yes, Base,
inline auto make_error_invoker( inline auto make_error_invoker(
std::integral_constant<handle_errors, handle_errors::plain>) noexcept { std::integral_constant<handle_errors, handle_errors::plain>) noexcept {
return [](auto&& callback, types::error_type&& error) { return [](auto&& callback, exception_t&& error) {
// Errors are not partial invoked // Errors are not partial invoked
// NOLINTNEXTLINE(hicpp-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg)
std::forward<decltype(callback)>(callback)(std::move(error)); std::forward<decltype(callback)>(callback)(std::move(error));
@ -353,17 +352,17 @@ inline auto make_error_invoker(
} }
inline auto make_error_invoker( inline auto make_error_invoker(
std::integral_constant<handle_errors, handle_errors::forward>) noexcept { std::integral_constant<handle_errors, handle_errors::forward>) noexcept {
return [](auto&& callback, types::error_type&& error) { return [](auto&& callback, exception_t&& error) {
// Errors are not partial invoked // Errors are not partial invoked
std::forward<decltype(callback)>(callback)( std::forward<decltype(callback)>(callback)(
types::dispatch_error_tag{}, exception_arg_t{},
std::move(error)); // NOLINT(hicpp-move-const-arg) std::move(error)); // NOLINT(hicpp-move-const-arg)
}; };
} }
template <handle_errors HandleErrors /* = plain or forward*/, typename Base> template <handle_errors HandleErrors /* = plain or forward*/, typename Base>
struct error_handler_base { struct error_handler_base {
void operator()(types::dispatch_error_tag, types::error_type error) && { void operator()(exception_arg_t, exception_t error) && {
// Just invoke the error handler, cancel the calling hierarchy after // Just invoke the error handler, cancel the calling hierarchy after
auto invoker = make_error_invoker( auto invoker = make_error_invoker(
std::integral_constant<handle_errors, HandleErrors>{}); std::integral_constant<handle_errors, HandleErrors>{});
@ -377,7 +376,7 @@ struct error_handler_base {
template <typename Base> template <typename Base>
struct error_handler_base<handle_errors::no, Base> { struct error_handler_base<handle_errors::no, Base> {
/// The operator which is called when an error occurred /// The operator which is called when an error occurred
void operator()(types::dispatch_error_tag tag, types::error_type error) && { void operator()(exception_arg_t tag, exception_t error) && {
// Forward the error to the next callback // Forward the error to the next callback
std::move(static_cast<Base*>(this)->next_callback_)(tag, std::move(error)); std::move(static_cast<Base*>(this)->next_callback_)(tag, std::move(error));
} }
@ -435,8 +434,8 @@ struct callback_base<hints::signature_hint_tag<Args...>, HandleResults,
} }
/// Resolves the continuation with the given error variable. /// Resolves the continuation with the given error variable.
void set_exception(types::error_type error) { void set_exception(exception_t error) {
std::move (*this)(types::dispatch_error_tag{}, std::move(error)); std::move (*this)(exception_arg_t{}, std::move(error));
} }
}; };
@ -459,7 +458,7 @@ struct final_callback : util::non_copyable {
void operator()(Args... /*args*/) && { void operator()(Args... /*args*/) && {
} }
void operator()(types::dispatch_error_tag, types::error_type error) && { void operator()(exception_arg_t, exception_t error) && {
(void)error; (void)error;
#ifndef CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS #ifndef CONTINUABLE_WITH_UNHANDLED_EXCEPTIONS
// There were unhandled errors inside the asynchronous call chain! // There were unhandled errors inside the asynchronous call chain!
@ -485,9 +484,9 @@ struct final_callback : util::non_copyable {
std::move (*this)(std::forward<Args>(args)...); std::move (*this)(std::forward<Args>(args)...);
} }
void set_exception(types::error_type error) { void set_exception(exception_t error) {
// NOLINTNEXTLINE(hicpp-move-const-arg) // NOLINTNEXTLINE(hicpp-move-const-arg)
std::move (*this)(types::dispatch_error_tag{}, std::move(error)); std::move (*this)(exception_arg_t{}, std::move(error));
} }
}; };
} // namespace callbacks } // namespace callbacks
@ -540,12 +539,10 @@ auto chain_continuation(Continuation&& continuation, Callback&& callback,
continuation.freeze(); continuation.freeze();
return attorney::create( return attorney::create(
[ [continuation = std::forward<Continuation>(continuation),
continuation = std::forward<Continuation>(continuation), callback = std::forward<Callback>(callback),
callback = std::forward<Callback>(callback), executor =
executor = std::forward<Executor>(executor) std::forward<Executor>(executor)](auto&& next_callback) mutable {
](auto&& next_callback) mutable {
// Invokes a continuation with a given callback. // Invokes a continuation with a given callback.
// Passes the next callback to the resulting continuable or // Passes the next callback to the resulting continuable or
// invokes the next callback directly if possible. // invokes the next callback directly if possible.

View File

@ -50,21 +50,19 @@ namespace detail {
/// Contains types used globally across the library /// Contains types used globally across the library
namespace types { namespace types {
#ifdef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE #ifdef CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
using error_type = CONTINUABLE_WITH_CUSTOM_ERROR_TYPE; using exception_t = CONTINUABLE_WITH_CUSTOM_ERROR_TYPE;
#else // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE #else // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
#ifndef CONTINUABLE_WITH_NO_EXCEPTIONS #ifndef CONTINUABLE_WITH_NO_EXCEPTIONS
/// Represents the error type when exceptions are enabled /// Represents the exception type when exceptions are enabled
using error_type = std::exception_ptr; using exception_t = std::exception_ptr;
#else // CONTINUABLE_WITH_NO_EXCEPTIONS #else // CONTINUABLE_WITH_NO_EXCEPTIONS
/// Represents the error type when exceptions are disabled /// Represents the error type when exceptions are disabled
using error_type = std::error_condition; using exception_t = std::error_condition;
#endif // CONTINUABLE_WITH_NO_EXCEPTIONS #endif // CONTINUABLE_WITH_NO_EXCEPTIONS
#endif // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE #endif // CONTINUABLE_WITH_CUSTOM_ERROR_TYPE
/// A tag which is used to execute the continuation inside the current thread /// A tag which is used to execute the continuation inside the current thread
struct this_thread_executor_tag {}; struct this_thread_executor_tag {};
/// A tag which is used to continue with an error
struct dispatch_error_tag {};
/// Marks a given callable object as transformation /// Marks a given callable object as transformation
template <typename T> template <typename T>

View File

@ -35,6 +35,7 @@
#include <cassert> #include <cassert>
#include <tuple> #include <tuple>
#include <experimental/coroutine> #include <experimental/coroutine>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/core/hints.hpp> #include <continuable/detail/core/hints.hpp>
#include <continuable/detail/core/types.hpp> #include <continuable/detail/core/types.hpp>
#include <continuable/detail/features.hpp> #include <continuable/detail/features.hpp>
@ -110,7 +111,7 @@ private:
} }
/// Resolve the continuation through an error /// Resolve the continuation through an error
void resolve(types::dispatch_error_tag, types::error_type error) { void resolve(exception_arg_t, exception_t error) {
result_.set_exception(std::move(error)); result_.set_exception(std::move(error));
} }
}; };

View File

@ -33,6 +33,7 @@
#include <type_traits> #include <type_traits>
#include <continuable/continuable-base.hpp> #include <continuable/continuable-base.hpp>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/features.hpp> #include <continuable/detail/features.hpp>
#include <continuable/detail/utility/traits.hpp> #include <continuable/detail/utility/traits.hpp>
#include <continuable/detail/utility/util.hpp> #include <continuable/detail/utility/util.hpp>
@ -48,7 +49,7 @@ namespace convert {
inline auto default_resolver() { inline auto default_resolver() {
return [](auto&& promise, auto&& e, auto&&... args) { return [](auto&& promise, auto&& e, auto&&... args) {
static_assert( static_assert(
std::is_convertible<std::decay_t<decltype(e)>, error_type>::value, std::is_convertible<std::decay_t<decltype(e)>, exception_t>::value,
"The given error type must be convertible to the error type used! " "The given error type must be convertible to the error type used! "
"Specify a custom resolver in order to apply a conversion to the " "Specify a custom resolver in order to apply a conversion to the "
"used error type."); "used error type.");
@ -65,30 +66,28 @@ template <typename... Result>
struct promisify_helper { struct promisify_helper {
template <typename Resolver, typename Callable, typename... Args> template <typename Resolver, typename Callable, typename... Args>
static auto from(Resolver&& resolver, Callable&& callable, Args&&... args) { static auto from(Resolver&& resolver, Callable&& callable, Args&&... args) {
return make_continuable<Result...>([ return make_continuable<Result...>(
resolver = std::forward<Resolver>(resolver), [resolver = std::forward<Resolver>(resolver),
args = traits::make_flat_tuple(std::forward<Callable>(callable), args = traits::make_flat_tuple(std::forward<Callable>(callable),
std::forward<Args>(args)...) std::forward<Args>(args)...)](
](auto&& promise) mutable { auto&& promise) mutable {
traits::unpack(
[promise = std::forward<decltype(promise)>(promise),
&resolver](auto&&... args) mutable {
// Call the resolver from with the promise and result
auto callback =
[resolver = std::move(resolver),
promise = std::move(promise)](auto&&... args) mutable {
resolver(std::move(promise),
std::forward<decltype(args)>(args)...);
};
traits::unpack( // Invoke the callback taking function
[ promise = std::forward<decltype(promise)>(promise), util::invoke(std::forward<decltype(args)>(args)...,
&resolver ](auto&&... args) mutable { std::move(callback));
},
// Call the resolver from with the promise and result std::move(args));
auto callback = [ });
resolver = std::move(resolver), promise = std::move(promise)
](auto&&... args) mutable {
resolver(std::move(promise),
std::forward<decltype(args)>(args)...);
};
// Invoke the callback taking function
util::invoke(std::forward<decltype(args)>(args)...,
std::move(callback));
},
std::move(args));
});
} }
}; };
} // namespace convert } // namespace convert

View File

@ -34,6 +34,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/core/types.hpp> #include <continuable/detail/core/types.hpp>
#include <continuable/detail/features.hpp> #include <continuable/detail/features.hpp>
#include <continuable/detail/utility/traits.hpp> #include <continuable/detail/utility/traits.hpp>
@ -53,7 +54,7 @@ void assert_async_completion(C&& continuable) {
// Workaround for our known GCC bug. // Workaround for our known GCC bug.
util::unused(std::forward<decltype(args)>(args)...); util::unused(std::forward<decltype(args)>(args)...);
}) })
.fail([](cti::error_type /*error*/) { .fail([](cti::exception_t /*error*/) {
// ... // ...
FAIL(); FAIL();
}); });
@ -72,7 +73,7 @@ void assert_async_exception_completion(C&& continuable) {
// ... // ...
FAIL(); FAIL();
}) })
.fail([called](cti::error_type /*error*/) { .fail([called](cti::exception_t /*error*/) {
ASSERT_FALSE(*called); ASSERT_FALSE(*called);
*called = true; *called = true;
}); });
@ -89,7 +90,7 @@ void assert_async_never_completed(C&& continuable) {
FAIL(); FAIL();
}) })
.fail([](cti::error_type /*error*/) { .fail([](cti::exception_t /*error*/) {
// ... // ...
FAIL(); FAIL();
}); });
@ -99,11 +100,10 @@ template <typename C, typename V>
void assert_async_validation(C&& continuable, V&& validator) { void assert_async_validation(C&& continuable, V&& validator) {
assert_async_completion( assert_async_completion(
std::forward<C>(continuable) std::forward<C>(continuable)
.then([validator = .then(
std::forward<V>(validator)](auto&&... args) mutable { [validator = std::forward<V>(validator)](auto&&... args) mutable {
validator(std::forward<decltype(args)>(args)...);
validator(std::forward<decltype(args)>(args)...); }));
}));
} }
/// Expects that the continuable is finished with the given arguments /// Expects that the continuable is finished with the given arguments
@ -113,18 +113,17 @@ void assert_async_binary_validation(V&& validator, C&& continuable,
using size = std::integral_constant<std::size_t, sizeof...(expected)>; using size = std::integral_constant<std::size_t, sizeof...(expected)>;
assert_async_validation(std::forward<C>(continuable), [ assert_async_validation(
expected_pack = std::make_tuple(std::forward<Args>(expected)...), std::forward<C>(continuable),
validator = std::forward<V>(validator) [expected_pack = std::make_tuple(std::forward<Args>(expected)...),
](auto&&... args) mutable { validator = std::forward<V>(validator)](auto&&... args) mutable {
static_assert(size::value == sizeof...(args),
"Async completion handler called with a different count "
"of arguments!");
static_assert(size::value == sizeof...(args), validator(std::make_tuple(std::forward<decltype(args)>(args)...),
"Async completion handler called with a different count " expected_pack);
"of arguments!"); });
validator(std::make_tuple(std::forward<decltype(args)>(args)...),
expected_pack);
});
} }
/// Expects that the continuable is finished with the given arguments /// Expects that the continuable is finished with the given arguments
@ -140,10 +139,9 @@ void assert_async_binary_exception_validation(V&& validator, C&& continuable,
// ... // ...
FAIL(); FAIL();
}) })
.fail([ .fail([called, validator = std::forward<decltype(validator)>(validator),
called, validator = std::forward<decltype(validator)>(validator), expected = std::forward<decltype(expected)>(expected)](
expected = std::forward<decltype(expected)>(expected) exception_t error) {
](types::error_type error) {
ASSERT_FALSE(*called); ASSERT_FALSE(*called);
*called = true; *called = true;

View File

@ -32,6 +32,7 @@
#define CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED #define CONTINUABLE_DETAIL_TRANSFORMS_HPP_INCLUDED
#include <future> #include <future>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/core/base.hpp> #include <continuable/detail/core/base.hpp>
#include <continuable/detail/core/hints.hpp> #include <continuable/detail/core/hints.hpp>
#include <continuable/detail/core/types.hpp> #include <continuable/detail/core/types.hpp>
@ -94,7 +95,7 @@ public:
} }
/// Resolves the promise through the exception /// Resolves the promise through the exception
void operator()(types::dispatch_error_tag, types::error_type error) { void operator()(exception_arg_t, exception_t error) {
#if defined(CONTINUABLE_HAS_EXCEPTIONS) #if defined(CONTINUABLE_HAS_EXCEPTIONS)
promise_.set_exception(error); promise_.set_exception(error);
#else #else

View File

@ -33,8 +33,8 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <continuable/continuable-primitives.hpp>
#include <continuable/detail/core/hints.hpp> #include <continuable/detail/core/hints.hpp>
#include <continuable/detail/core/types.hpp>
#include <continuable/detail/utility/flat-variant.hpp> #include <continuable/detail/utility/flat-variant.hpp>
namespace cti { namespace cti {
@ -45,7 +45,7 @@ namespace container {
/// exceptions are used. /// exceptions are used.
template <typename T> template <typename T>
class expected { class expected {
flat_variant<T, types::error_type> variant_; flat_variant<T, exception_t> variant_;
public: public:
explicit expected() = default; explicit expected() = default;
@ -57,15 +57,14 @@ public:
explicit expected(T value) : variant_(std::move(value)) { explicit expected(T value) : variant_(std::move(value)) {
} }
explicit expected(types::error_type exception) explicit expected(exception_t exception) : variant_(std::move(exception)) {
: variant_(std::move(exception)) {
} }
expected& operator=(T value) { expected& operator=(T value) {
variant_ = std::move(value); variant_ = std::move(value);
return *this; return *this;
} }
expected& operator=(types::error_type exception) { expected& operator=(exception_t exception) {
variant_ = std::move(exception); variant_ = std::move(exception);
return *this; return *this;
} }
@ -73,7 +72,7 @@ public:
void set_value(T value) { void set_value(T value) {
variant_ = std::move(value); variant_ = std::move(value);
} }
void set_exception(types::error_type exception) { void set_exception(exception_t exception) {
variant_ = std::move(exception); variant_ = std::move(exception);
} }
@ -81,7 +80,7 @@ public:
return variant_.template is<T>(); return variant_.template is<T>();
} }
bool is_exception() const noexcept { bool is_exception() const noexcept {
return variant_.template is<types::error_type>(); return variant_.template is<exception_t>();
} }
explicit constexpr operator bool() const noexcept { explicit constexpr operator bool() const noexcept {
@ -94,11 +93,11 @@ public:
T const& get_value() const noexcept { T const& get_value() const noexcept {
return variant_.template cast<T>(); return variant_.template cast<T>();
} }
types::error_type& get_exception() noexcept { exception_t& get_exception() noexcept {
return variant_.template cast<types::error_type>(); return variant_.template cast<exception_t>();
} }
types::error_type const& get_exception() const noexcept { exception_t const& get_exception() const noexcept {
return variant_.template cast<types::error_type>(); return variant_.template cast<exception_t>();
} }
T& operator*() noexcept { T& operator*() noexcept {

View File

@ -40,7 +40,7 @@ TYPED_TEST(single_dimension_tests, are_yielding_error_result) {
TYPED_TEST(single_dimension_tests, are_never_completed_after_error_handled) { TYPED_TEST(single_dimension_tests, are_never_completed_after_error_handled) {
auto handled = std::make_shared<bool>(false); auto handled = std::make_shared<bool>(false);
auto continuation = this->supply_exception(supply_test_exception()) auto continuation = this->supply_exception(supply_test_exception())
.fail([handled](cti::error_type) { .fail([handled](cti::exception_t) {
ASSERT_FALSE(*handled); ASSERT_FALSE(*handled);
*handled = true; *handled = true;
}); });
@ -84,7 +84,7 @@ TYPED_TEST(single_dimension_tests, are_result_error_accepting) {
ASSERT_FALSE(*handled); ASSERT_FALSE(*handled);
*handled = true; *handled = true;
}, },
[](cti::dispatch_error_tag, cti::error_type) { [](cti::exception_arg_t, cti::exception_t) {
// ... // ...
FAIL(); FAIL();
})); }));
@ -102,7 +102,7 @@ TYPED_TEST(single_dimension_tests, are_flow_error_accepting) {
// ... // ...
FAIL(); FAIL();
}, },
[handled](cti::dispatch_error_tag, cti::error_type) { [handled](cti::exception_arg_t, cti::exception_t) {
ASSERT_FALSE(*handled); ASSERT_FALSE(*handled);
*handled = true; *handled = true;
})); }));

View File

@ -31,7 +31,7 @@ struct my_callable {
void operator()(std::string) && { void operator()(std::string) && {
// ... // ...
} }
void operator()(cti::dispatch_error_tag, cti::error_type) && { void operator()(cti::exception_arg_t, cti::exception_t) && {
// ... // ...
} }
}; };
@ -54,7 +54,7 @@ TEST(simple_compilation_tests, error_compile_tests) {
.then([](int) { .then([](int) {
// ... // ...
}) })
.fail([](cti::error_type) { .fail([](cti::exception_t) {
// ... // ...
}); });
@ -62,7 +62,7 @@ TEST(simple_compilation_tests, error_compile_tests) {
.then([](std::string, std::string) { .then([](std::string, std::string) {
// ... // ...
}) })
.fail([](cti::error_type) { .fail([](cti::exception_t) {
// ... // ...
}) })
.apply([](auto&& me) { .apply([](auto&& me) {
@ -74,7 +74,7 @@ TEST(simple_compilation_tests, error_compile_tests) {
.then([](std::string) { .then([](std::string) {
// ... // ...
}) })
.fail([](cti::error_type) { .fail([](cti::exception_t) {
// ... // ...
}); });
@ -82,7 +82,7 @@ TEST(simple_compilation_tests, error_compile_tests) {
.then([](std::string, std::string) { .then([](std::string, std::string) {
// ... // ...
}) })
.fail([](cti::error_type) { .fail([](cti::exception_t) {
// ... // ...
}); });
} }
@ -117,7 +117,7 @@ TEST(simple_compilation_tests, connection_compile_tests) {
// ... // ...
}); });
cti::when_seq(cti::make_exceptional_continuable<void>(cti::error_type{})) cti::when_seq(cti::make_exceptional_continuable<void>(cti::exception_t{}))
.fail([](auto) { .fail([](auto) {
// ... // ...
}); });

View File

@ -28,7 +28,7 @@
#include <test-continuable.hpp> #include <test-continuable.hpp>
using cti::detail::container::expected; using cti::detail::container::expected;
using cti::detail::types::error_type; using cti::exception_t;
static int const CANARY = 373671; static int const CANARY = 373671;
@ -73,7 +73,7 @@ TYPED_TEST(expected_all_tests, can_carry_errors) {
} }
{ {
TypeParam e(error_type{}); TypeParam e(exception_t{});
EXPECT_FALSE(bool(e)); EXPECT_FALSE(bool(e));
EXPECT_FALSE(e.is_value()); EXPECT_FALSE(e.is_value());
@ -97,7 +97,7 @@ TYPED_TEST(expected_all_tests, is_move_constructible) {
} }
{ {
TypeParam e(TypeParam(error_type{})); TypeParam e(TypeParam(exception_t{}));
EXPECT_FALSE(bool(e)); EXPECT_FALSE(bool(e));
EXPECT_FALSE(e.is_value()); EXPECT_FALSE(e.is_value());
EXPECT_TRUE(e.is_exception()); EXPECT_TRUE(e.is_exception());
@ -116,7 +116,7 @@ TYPED_TEST(expected_all_tests, is_value_move_assignable) {
} }
TYPED_TEST(expected_all_tests, is_error_move_assignable) { TYPED_TEST(expected_all_tests, is_error_move_assignable) {
TypeParam old(error_type{}); TypeParam old(exception_t{});
TypeParam e; TypeParam e;
e = std::move(old); e = std::move(old);
@ -138,7 +138,7 @@ TYPED_TEST(expected_all_tests, is_value_assignable) {
{ {
TypeParam e; TypeParam e;
e = error_type{}; e = exception_t{};
EXPECT_FALSE(bool(e)); EXPECT_FALSE(bool(e));
EXPECT_FALSE(e.is_value()); EXPECT_FALSE(e.is_value());
@ -158,7 +158,7 @@ TEST(expected_copyable_tests, is_copy_constructible) {
} }
{ {
copyable_type const e_old(error_type{}); copyable_type const e_old(exception_t{});
copyable_type e(e_old); copyable_type e(e_old);
EXPECT_FALSE(bool(e)); EXPECT_FALSE(bool(e));
@ -180,7 +180,7 @@ TEST(expected_copyable_tests, is_copy_assignable) {
} }
{ {
copyable_type const e_old(error_type{}); copyable_type const e_old(exception_t{});
copyable_type e; copyable_type e;
e = e_old; e = e_old;

View File

@ -25,7 +25,7 @@
template <typename T, typename Callback> template <typename T, typename Callback>
void async_supply(T&& value, Callback&& callback) { void async_supply(T&& value, Callback&& callback) {
std::forward<Callback>(callback)(cti::error_type{}, std::forward<T>(value)); std::forward<Callback>(callback)(cti::exception_t{}, std::forward<T>(value));
} }
TEST(promisify_tests, promisify_from) { TEST(promisify_tests, promisify_from) {
@ -56,7 +56,7 @@ TEST(promisify_tests, promisify_with) {
auto c = cti::promisify<int>::with( auto c = cti::promisify<int>::with(
[](auto&& promise, auto&& /*e*/, int const& value) { [](auto&& promise, auto&& /*e*/, int const& value) {
EXPECT_EQ(value, 36354); EXPECT_EQ(value, 36354);
promise.set_exception(cti::error_type{}); promise.set_exception(cti::exception_t{});
}, },
[&](auto&&... args) { [&](auto&&... args) {
async_supply(std::forward<decltype(args)>(args)...); async_supply(std::forward<decltype(args)>(args)...);