mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 16:56:44 +08:00
Implement make_plain to make it possible to not handle special objects in handlers
This commit is contained in:
parent
4c807aec75
commit
7491022d0f
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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_;
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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( //
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user