Implement make_plain to make it possible to not handle special objects in handlers

This commit is contained in:
Denis Blank 2019-01-14 21:02:22 +01:00
parent 4c807aec75
commit 7491022d0f
8 changed files with 105 additions and 12 deletions

View File

@ -228,15 +228,17 @@ continuable_base(continuable_base<OData, Annotation>&& other)
/// | `Arg` | `continuable_base with <Arg>` |
/// | `std::pair<First, Second>` | `continuable_base with <First, Second>` |
/// | `std::tuple<Args...>` | `continuable_base with <Args...>` |
/// | `result<Args...>` | `continuable_base with <Args...>` |
/// | `cti::result<Args...>` | `continuable_base with <Args...>` |
/// | `continuable_base<Arg...>` | `continuable_base with <Args...>` |
/// Which means the result type of the continuable_base is equal to
/// the plain types the callback returns (`std::tuple` and
/// `std::pair` arguments are unwrapped).
/// A single continuable_base as argument is resolved and the result
/// type is equal to the resolved continuable_base.
/// A result<...> can be used to cancel the continuation or to
/// A cti::result can be used to cancel the continuation or to
/// transition to the exception handler.
/// The special unwrapping of types can be disabled through wrapping
/// such objects through a call to cti::make_plain.
/// Consider the following examples:
/// ```cpp
/// http_request("github.com")
@ -864,8 +866,8 @@ constexpr auto make_continuable(Continuation&& continuation) {
/// \since 3.0.0
template <typename... Args>
auto make_ready_continuable(Args&&... args) {
using detail::base::ready_continuation;
using detail::identity;
using detail::base::ready_continuation;
using detail::traits::unrefcv_t;
return detail::base::attorney::create_from_raw(
ready_continuation<unrefcv_t<Args>...>{std::forward<Args>(args)...},
@ -926,6 +928,33 @@ auto make_cancelling_continuable() {
return make_continuable<Signature...>([](auto&&) { /* ... */ });
}
/// Can be used to disable the special meaning for a returned value in
/// asynchronous handler functions.
///
/// Several types have a special meaning when being returned from a callable
/// passed to asynchronous handler functions like:
/// - continuable_base::then
/// - continuable_base::fail
/// - continuable_base::next
///
/// For instance such types are std::tuple, std::pair and cti::result.
///
/// Wrapping such an object through a call to make_plain disables the special
/// meaning for such objects as shown below:
/// ```cpp
/// continuable<result<int, int> c = http_request("example.com")
/// .then([](std::string content) {
/// return make_plain(make_result(0, 1));
/// })
/// ```
///
/// \since 4.0.0
///
template <typename T>
auto make_plain(T&& value) {
return plain_t<detail::traits::unrefcv_t<T>>(std::forward<T>(value));
}
/// Can be used to recover to from a failure handler,
/// the result handler which comes after will be called with the
/// corresponding result.

View File

@ -62,6 +62,7 @@ namespace cti {
/// of a continuable_base or promise_base.
///
/// \since 4.0.0
///
template <typename... Args>
using signature_arg_t = detail::identity<Args...>;
@ -70,6 +71,7 @@ using signature_arg_t = detail::identity<Args...>;
/// without having side effects.
///
/// \since 4.0.0
///
struct is_ready_arg_t {};
/// Represents the tag type that is used to query the continuation
@ -78,6 +80,7 @@ struct is_ready_arg_t {};
/// It's required that the query of is_ready_arg_t returns true.
///
/// \since 4.0.0
///
struct query_arg_t {};
/// Represents the tag type that is used to disambiguate the
@ -86,6 +89,7 @@ struct query_arg_t {};
/// \note see continuable::next for details.
///
/// \since 4.0.0
///
struct exception_arg_t {};
/// \copydoc exception_arg_t
@ -96,7 +100,7 @@ struct exception_arg_t {};
///
[[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;
typedef exception_arg_t dispatch_error_tag;
/// Represents the type that is used as exception type
///
@ -107,6 +111,7 @@ struct exception_arg_t {};
/// defining `CONTINUABLE_WITH_CUSTOM_ERROR_TYPE`.
///
/// \since 4.0.0
///
using exception_t = detail::types::exception_t;
/// \copydoc exception_t
@ -117,7 +122,16 @@ using exception_t = detail::types::exception_t;
///
[[deprecated("The error_type was replaced by exception_t and will "
"be removed in a later major version!")]] //
typedef exception_t error_type;
typedef exception_t error_type;
/// Represents the type that is used to disable the special meaning of types
/// which are returned by a asynchronous result handler.
/// See cti::plain for details.
///
/// \since 4.0.0
///
template <typename T>
using plain_t = detail::types::plain_tag<T>;
/// \}
} // namespace cti

View File

@ -257,6 +257,11 @@ public:
return result{init_arg_t{}, std::move(exception)};
}
/// Creates an empty result
static result empty() {
return result{empty_result{}};
}
private:
detail::container::flat_variant<surrogate_t, exception_t> variant_;
};

View File

@ -329,6 +329,23 @@ constexpr auto invoker_of(identity<T>) {
identify<T>{});
}
/// - plain_tag<?> -> next_callback(?)
template <typename T>
constexpr auto invoker_of(identity<types::plain_tag<T>>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN
types::plain_tag<T> result =
invoke_callback(std::forward<decltype(callback)>(callback),
std::forward<decltype(args)>(args)...);
invoke_no_except(std::forward<decltype(next_callback)>(next_callback),
std::move(result).consume());
CONTINUABLE_BLOCK_TRY_END
},
identify<T>{});
}
/// - void -> next_callback()
inline auto invoker_of(identity<void>) {
return make_invoker(
@ -469,10 +486,8 @@ void on_executor(Executor&& executor, Invoker&& invoker, Args&&... args) {
// Create a worker object which when invoked calls the callback with the
// the returned arguments.
auto work = [
invoker = std::forward<Invoker>(invoker),
args = std::make_tuple(std::forward<Args>(args)...)
]() mutable {
auto work = [invoker = std::forward<Invoker>(invoker),
args = std::make_tuple(std::forward<Args>(args)...)]() mutable {
traits::unpack(
[&](auto&&... captured_args) {
// Just use the packed dispatch method which dispatches the work on

View File

@ -77,6 +77,20 @@ public:
/// Tag for constructing an empty promise_base .
struct promise_no_init_arg_t {};
/// Marks a given callable object as transformation
template <typename T>
class plain_tag {
T value_;
public:
explicit plain_tag(T value) : value_(std::move(value)) {
}
T&& consume() && {
return std::move(value_);
}
};
} // namespace types
} // namespace detail
} // namespace cti

View File

@ -160,12 +160,12 @@ auto make_range_looper(Callable&& callable, Begin&& begin, End&& end) {
begin = std::forward<Begin>(begin),
end = std::forward<End>(end)]() mutable {
return util::invoke(callable, begin)
.then([&begin, &end]() mutable -> std::tuple<result<>> {
.then([&begin, &end]() mutable -> plain_t<result<>> {
// begin and end stays valid over the `then` here
if (++begin != end) {
return std::make_tuple(result<>(empty_result{}));
return make_plain(result<>::empty());
} else {
return std::make_tuple(make_result());
return make_plain(make_result());
}
});
};

View File

@ -60,6 +60,8 @@ namespace cti {
/// \returns A continuable_base which asynchronous result type will
/// be computated with the same rules as continuable_base::then .
///
/// \since 4.0.0
///
template <typename Callable, typename... Args>
auto async(Callable&& callable, Args&&... args) {
return detail::operations::async(std::forward<Callable>(callable),

View File

@ -38,12 +38,26 @@
namespace cti {
/// \ingroup Operations
/// \{
/// Can be used to create an asynchronous loop.
///
/// The callable will be called repeatedly until it returns a
/// cti::continuable_base which then resolves to present cti::result.
///
/// \param callable The callable type which must return a cti::continuable_base
/// which then resolves to a cti::result of arbitrary values.
///
/// \since 4.0.0
///
template <typename Callable, typename... Args>
auto loop(Callable&& callable, Args&&... args) {
return detail::operations::loop(std::forward<Callable>(callable),
std::forward<Args>(args)...);
}
///
/// \since 4.0.0
///
template <typename Callable, typename Iterator>
auto range_loop(Callable&& callable, Iterator begin, Iterator end) {
return detail::operations::loop( //