diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index ff7a830..3e87317 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -228,15 +228,17 @@ continuable_base(continuable_base&& other) /// | `Arg` | `continuable_base with ` | /// | `std::pair` | `continuable_base with ` | /// | `std::tuple` | `continuable_base with ` | - /// | `result` | `continuable_base with ` | + /// | `cti::result` | `continuable_base with ` | /// | `continuable_base` | `continuable_base with ` | /// 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 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...>{std::forward(args)...}, @@ -926,6 +928,33 @@ auto make_cancelling_continuable() { return make_continuable([](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 c = http_request("example.com") +/// .then([](std::string content) { +/// return make_plain(make_result(0, 1)); +/// }) +/// ``` +/// +/// \since 4.0.0 +/// +template +auto make_plain(T&& value) { + return plain_t>(std::forward(value)); +} + /// Can be used to recover to from a failure handler, /// the result handler which comes after will be called with the /// corresponding result. diff --git a/include/continuable/continuable-primitives.hpp b/include/continuable/continuable-primitives.hpp index d680255..12aae3b 100644 --- a/include/continuable/continuable-primitives.hpp +++ b/include/continuable/continuable-primitives.hpp @@ -62,6 +62,7 @@ namespace cti { /// of a continuable_base or promise_base. /// /// \since 4.0.0 +/// template using signature_arg_t = detail::identity; @@ -70,6 +71,7 @@ using signature_arg_t = detail::identity; /// 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 +using plain_t = detail::types::plain_tag; /// \} } // namespace cti diff --git a/include/continuable/continuable-result.hpp b/include/continuable/continuable-result.hpp index 52d1f07..7daff9c 100644 --- a/include/continuable/continuable-result.hpp +++ b/include/continuable/continuable-result.hpp @@ -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 variant_; }; diff --git a/include/continuable/detail/core/base.hpp b/include/continuable/detail/core/base.hpp index c315b79..c1814f2 100644 --- a/include/continuable/detail/core/base.hpp +++ b/include/continuable/detail/core/base.hpp @@ -329,6 +329,23 @@ constexpr auto invoker_of(identity) { identify{}); } +/// - plain_tag -> next_callback(?) +template +constexpr auto invoker_of(identity>) { + return make_invoker( + [](auto&& callback, auto&& next_callback, auto&&... args) { + CONTINUABLE_BLOCK_TRY_BEGIN + types::plain_tag result = + invoke_callback(std::forward(callback), + std::forward(args)...); + + invoke_no_except(std::forward(next_callback), + std::move(result).consume()); + CONTINUABLE_BLOCK_TRY_END + }, + identify{}); +} + /// - void -> next_callback() inline auto invoker_of(identity) { 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), - args = std::make_tuple(std::forward(args)...) - ]() mutable { + auto work = [invoker = std::forward(invoker), + args = std::make_tuple(std::forward(args)...)]() mutable { traits::unpack( [&](auto&&... captured_args) { // Just use the packed dispatch method which dispatches the work on diff --git a/include/continuable/detail/core/types.hpp b/include/continuable/detail/core/types.hpp index ec5e0c2..0ec8737 100644 --- a/include/continuable/detail/core/types.hpp +++ b/include/continuable/detail/core/types.hpp @@ -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 +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 diff --git a/include/continuable/detail/operations/loop.hpp b/include/continuable/detail/operations/loop.hpp index e663b87..76f62ce 100644 --- a/include/continuable/detail/operations/loop.hpp +++ b/include/continuable/detail/operations/loop.hpp @@ -160,12 +160,12 @@ auto make_range_looper(Callable&& callable, Begin&& begin, End&& end) { begin = std::forward(begin), end = std::forward(end)]() mutable { return util::invoke(callable, begin) - .then([&begin, &end]() mutable -> std::tuple> { + .then([&begin, &end]() mutable -> plain_t> { // 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()); } }); }; diff --git a/include/continuable/operations/async.hpp b/include/continuable/operations/async.hpp index 460eb9f..7ad0a8f 100644 --- a/include/continuable/operations/async.hpp +++ b/include/continuable/operations/async.hpp @@ -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 auto async(Callable&& callable, Args&&... args) { return detail::operations::async(std::forward(callable), diff --git a/include/continuable/operations/loop.hpp b/include/continuable/operations/loop.hpp index 773e8df..dd4f569 100644 --- a/include/continuable/operations/loop.hpp +++ b/include/continuable/operations/loop.hpp @@ -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 auto loop(Callable&& callable, Args&&... args) { return detail::operations::loop(std::forward(callable), std::forward(args)...); } +/// +/// \since 4.0.0 +/// template auto range_loop(Callable&& callable, Iterator begin, Iterator end) { return detail::operations::loop( //