mirror of
https://github.com/Naios/continuable.git
synced 2026-02-07 10:19:46 +08:00
Initial work on routing the arguments correctly when using result<...>
This commit is contained in:
parent
7767ce6fbb
commit
ba9ff9fce0
@ -39,11 +39,23 @@
|
|||||||
#include <continuable/detail/utility/traits.hpp>
|
#include <continuable/detail/utility/traits.hpp>
|
||||||
|
|
||||||
namespace cti {
|
namespace cti {
|
||||||
/// A class which is convertible to any result and that definitly holds no
|
/// \defgroup Result Result
|
||||||
/// value so the real result gets invalidated when
|
/// provides the \ref result class and corresponding utility functions to work
|
||||||
/// this object is passed to it
|
/// with the result of an asynchronous operation which can possibly yield:
|
||||||
|
/// - *no result*: If the operation didn't finish
|
||||||
|
/// - *a value*: If the operation finished successfully
|
||||||
|
/// - *an exception*: If the operation finished with an exception
|
||||||
|
/// \{
|
||||||
|
|
||||||
|
/// A class which is convertible to any \ref result and that definitly holds no
|
||||||
|
/// value so the real result gets invalidated when this object is passed to it.
|
||||||
struct empty_result {};
|
struct empty_result {};
|
||||||
|
|
||||||
|
/// Returns a new empty result
|
||||||
|
inline empty_result make_empty_result() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/// A class which is convertible to any result and that definitly holds
|
/// A class which is convertible to any result and that definitly holds
|
||||||
/// an exception which is then passed to the converted result object.
|
/// an exception which is then passed to the converted result object.
|
||||||
class exceptional_result {
|
class exceptional_result {
|
||||||
@ -68,24 +80,38 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets an exception
|
||||||
void set_exception(exception_t exception) {
|
void set_exception(exception_t exception) {
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||||
exception_ = std::move(exception);
|
exception_ = std::move(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the contained exception
|
||||||
exception_t& get_exception() & noexcept {
|
exception_t& get_exception() & noexcept {
|
||||||
return exception_;
|
return exception_;
|
||||||
}
|
}
|
||||||
|
/// \copydoc get_exception
|
||||||
exception_t const& get_exception() const& noexcept {
|
exception_t const& get_exception() const& noexcept {
|
||||||
return exception_;
|
return exception_;
|
||||||
}
|
}
|
||||||
|
/// \copydoc get_exception
|
||||||
exception_t&& get_exception() && noexcept {
|
exception_t&& get_exception() && noexcept {
|
||||||
return std::move(exception_);
|
return std::move(exception_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A class similar to the one in the result proposal,
|
/// Returns a new exceptional result from the given exception
|
||||||
/// however it's capable of carrying an exception_t.
|
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||||
|
inline exceptional_result make_exceptional_result(exception_t exception) {
|
||||||
|
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
||||||
|
return exceptional_result{std::move(exception)};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The result class can carry the three kinds of results an asynchronous
|
||||||
|
/// operation can return: no result, a value or an exception.
|
||||||
|
/// - *no result*: If the operation didn't finish
|
||||||
|
/// - *a value*: If the operation finished successfully
|
||||||
|
/// - *an exception*: If the operation finished with an exception
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
class result {
|
class result {
|
||||||
using trait_t = detail::result_trait<T...>;
|
using trait_t = detail::result_trait<T...>;
|
||||||
@ -108,7 +134,8 @@ public:
|
|||||||
}
|
}
|
||||||
explicit result(exception_t exception) : variant_(std::move(exception)) {
|
explicit result(exception_t exception) : variant_(std::move(exception)) {
|
||||||
}
|
}
|
||||||
result(empty_result){};
|
result(empty_result) {
|
||||||
|
}
|
||||||
result(exceptional_result exceptional_result)
|
result(exceptional_result exceptional_result)
|
||||||
: variant_(std::move(exceptional_result.get_exception())) {
|
: variant_(std::move(exceptional_result.get_exception())) {
|
||||||
}
|
}
|
||||||
@ -146,6 +173,7 @@ public:
|
|||||||
return is_value();
|
return is_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the
|
||||||
decltype(auto) get_value() & noexcept {
|
decltype(auto) get_value() & noexcept {
|
||||||
return trait_t::unwrap(variant_.template cast<surrogate_t>());
|
return trait_t::unwrap(variant_.template cast<surrogate_t>());
|
||||||
}
|
}
|
||||||
@ -184,16 +212,7 @@ template <typename... T>
|
|||||||
auto make_result(T&&... values) {
|
auto make_result(T&&... values) {
|
||||||
return result<detail::traits::unrefcv_t<T>...>(std::forward<T>(values)...);
|
return result<detail::traits::unrefcv_t<T>...>(std::forward<T>(values)...);
|
||||||
}
|
}
|
||||||
|
/// \}
|
||||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
|
||||||
inline exceptional_result make_exceptional_result(exception_t exception) {
|
|
||||||
// NOLINTNEXTLINE(hicpp-move-const-arg, performance-move-const-arg)
|
|
||||||
return exceptional_result{std::move(exception)};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline empty_result make_empty_result() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|
||||||
#endif // CONTINUABLE_RESULT_HPP_INCLUDED
|
#endif // CONTINUABLE_RESULT_HPP_INCLUDED
|
||||||
|
|||||||
@ -159,9 +159,9 @@ constexpr auto make_invoker(T&& invoke, hints::signature_hint_tag<Args...>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// - continuable<?...> -> result(next_callback);
|
/// - continuable<?...> -> result(next_callback);
|
||||||
template <typename Hint, typename Data, typename Annotation>
|
template <typename Data, typename Annotation>
|
||||||
constexpr auto
|
constexpr auto
|
||||||
invoker_of(Hint, traits::identity<continuable_base<Data, Annotation>>) {
|
invoker_of(traits::identity<continuable_base<Data, Annotation>>) {
|
||||||
/// Get the hint of the unwrapped returned continuable
|
/// Get the hint of the unwrapped returned continuable
|
||||||
using Type =
|
using Type =
|
||||||
decltype(std::declval<continuable_base<Data, Annotation>>().finish());
|
decltype(std::declval<continuable_base<Data, Annotation>>().finish());
|
||||||
@ -184,8 +184,8 @@ invoker_of(Hint, traits::identity<continuable_base<Data, Annotation>>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// - ? -> next_callback(?)
|
/// - ? -> next_callback(?)
|
||||||
template <typename Hint, typename T>
|
template <typename T>
|
||||||
constexpr auto invoker_of(Hint, traits::identity<T>) {
|
constexpr auto invoker_of(traits::identity<T>) {
|
||||||
return make_invoker(
|
return make_invoker(
|
||||||
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||||
CONTINUABLE_BLOCK_TRY_BEGIN
|
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||||
@ -201,8 +201,7 @@ constexpr auto invoker_of(Hint, traits::identity<T>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// - void -> next_callback()
|
/// - void -> next_callback()
|
||||||
template <typename Hint>
|
inline auto invoker_of(traits::identity<void>) {
|
||||||
auto invoker_of(Hint, traits::identity<void>) {
|
|
||||||
return make_invoker(
|
return make_invoker(
|
||||||
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||||
CONTINUABLE_BLOCK_TRY_BEGIN
|
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||||
@ -216,52 +215,73 @@ auto invoker_of(Hint, traits::identity<void>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// - empty_result -> <cancel>
|
/// - empty_result -> <cancel>
|
||||||
template <typename Hint>
|
inline auto invoker_of(traits::identity<empty_result>) {
|
||||||
auto invoker_of(Hint, traits::identity<empty_result>) {
|
|
||||||
return make_invoker(
|
return make_invoker(
|
||||||
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||||
util::unused(callback, next_callback, args...);
|
(void)next_callback;
|
||||||
// TODO
|
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||||
/*CONTINUABLE_BLOCK_TRY_BEGIN
|
empty_result result =
|
||||||
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
||||||
std::forward<decltype(args)>(args)...);
|
std::forward<decltype(args)>(args)...);
|
||||||
invoke_no_except(
|
|
||||||
std::forward<decltype(next_callback)>(next_callback));
|
// Don't invoke anything here since returning an empty result
|
||||||
CONTINUABLE_BLOCK_TRY_END*/
|
// cancels the asynchronous chain effectively.
|
||||||
|
(void)result;
|
||||||
|
CONTINUABLE_BLOCK_TRY_END
|
||||||
},
|
},
|
||||||
traits::identity<>{});
|
traits::identity<>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// - exceptional_result -> Hint
|
/// - exceptional_result -> <throw>
|
||||||
template <typename Hint>
|
inline auto invoker_of(traits::identity<exceptional_result>) {
|
||||||
auto invoker_of(Hint, traits::identity<exceptional_result>) {
|
|
||||||
return make_invoker(
|
return make_invoker(
|
||||||
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||||
util::unused(callback, next_callback, args...);
|
util::unused(callback, next_callback, args...);
|
||||||
// TODO
|
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||||
/*CONTINUABLE_BLOCK_TRY_BEGIN
|
exceptional_result result =
|
||||||
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
||||||
std::forward<decltype(args)>(args)...);
|
std::forward<decltype(args)>(args)...);
|
||||||
invoke_no_except(
|
|
||||||
std::forward<decltype(next_callback)>(next_callback));
|
// Forward the exception to the next available handler
|
||||||
CONTINUABLE_BLOCK_TRY_END*/
|
invoke_no_except(std::forward<decltype(next_callback)>(next_callback),
|
||||||
|
exception_arg_t{},
|
||||||
|
std::move(result).get_exception());
|
||||||
|
CONTINUABLE_BLOCK_TRY_END
|
||||||
},
|
},
|
||||||
traits::identity<>{});
|
traits::identity<>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// - result<Args...> -> Args...
|
/// - result<?...> -> next_callback(?...)
|
||||||
template <typename Hint, typename... Args>
|
template <typename... Args>
|
||||||
auto invoker_of(Hint, traits::identity<result<Args...>>) {
|
auto invoker_of(traits::identity<result<Args...>>) {
|
||||||
return make_invoker(
|
return make_invoker(
|
||||||
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
[](auto&& callback, auto&& next_callback, auto&&... args) {
|
||||||
util::unused(callback, next_callback, args...);
|
CONTINUABLE_BLOCK_TRY_BEGIN
|
||||||
// TODO
|
result<Args...> result =
|
||||||
/*CONTINUABLE_BLOCK_TRY_BEGIN
|
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
||||||
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
std::forward<decltype(args)>(args)...);
|
||||||
std::forward<decltype(args)>(args)...);
|
//
|
||||||
invoke_no_except(
|
if (result.is_value()) {
|
||||||
std::forward<decltype(next_callback)>(next_callback));
|
// Workaround for MSVC not capturing the reference
|
||||||
CONTINUABLE_BLOCK_TRY_END*/
|
// correctly inside the lambda.
|
||||||
|
using Next = decltype(next_callback);
|
||||||
|
|
||||||
|
traits::unpack(
|
||||||
|
[&](auto&&... types) {
|
||||||
|
/// TODO Add inplace resolution here
|
||||||
|
|
||||||
|
invoke_no_except(std::forward<Next>(next_callback),
|
||||||
|
std::forward<decltype(types)>(types)...);
|
||||||
|
},
|
||||||
|
std::move(result));
|
||||||
|
|
||||||
|
} else if (result.is_exception()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise the result is empty and we are cancelling our
|
||||||
|
// asynchronous chain.
|
||||||
|
CONTINUABLE_BLOCK_TRY_END
|
||||||
},
|
},
|
||||||
traits::identity<Args...>{});
|
traits::identity<Args...>{});
|
||||||
}
|
}
|
||||||
@ -275,8 +295,8 @@ inline auto sequenced_unpack_invoker() {
|
|||||||
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
util::partial_invoke(std::forward<decltype(callback)>(callback),
|
||||||
std::forward<decltype(args)>(args)...);
|
std::forward<decltype(args)>(args)...);
|
||||||
|
|
||||||
// Workaround for MSVC not capturing the reference correctly inside
|
// Workaround for MSVC not capturing the reference
|
||||||
// the lambda.
|
// correctly inside the lambda.
|
||||||
using Next = decltype(next_callback);
|
using Next = decltype(next_callback);
|
||||||
|
|
||||||
traits::unpack(
|
traits::unpack(
|
||||||
@ -292,15 +312,15 @@ inline auto sequenced_unpack_invoker() {
|
|||||||
} // namespace decoration
|
} // namespace decoration
|
||||||
|
|
||||||
// - std::pair<?, ?> -> next_callback(?, ?)
|
// - std::pair<?, ?> -> next_callback(?, ?)
|
||||||
template <typename Hint, typename First, typename Second>
|
template <typename First, typename Second>
|
||||||
constexpr auto invoker_of(Hint, traits::identity<std::pair<First, Second>>) {
|
constexpr auto invoker_of(traits::identity<std::pair<First, Second>>) {
|
||||||
return make_invoker(sequenced_unpack_invoker(),
|
return make_invoker(sequenced_unpack_invoker(),
|
||||||
traits::identity<First, Second>{});
|
traits::identity<First, Second>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
// - std::tuple<?...> -> next_callback(?...)
|
// - std::tuple<?...> -> next_callback(?...)
|
||||||
template <typename Hint, typename... Args>
|
template <typename... Args>
|
||||||
constexpr auto invoker_of(Hint, traits::identity<std::tuple<Args...>>) {
|
constexpr auto invoker_of(traits::identity<std::tuple<Args...>>) {
|
||||||
return make_invoker(sequenced_unpack_invoker(), traits::identity<Args...>{});
|
return make_invoker(sequenced_unpack_invoker(), traits::identity<Args...>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,9 +399,7 @@ struct result_handler_base<handle_results::yes, Base,
|
|||||||
std::move(static_cast<Base*>(this)->callback_), std::move(args)...))>{};
|
std::move(static_cast<Base*>(this)->callback_), std::move(args)...))>{};
|
||||||
|
|
||||||
// Pick the correct invoker that handles decorating of the result
|
// Pick the correct invoker that handles decorating of the result
|
||||||
auto invoker =
|
auto invoker = decoration::invoker_of(result);
|
||||||
decoration::invoker_of(hints::signature_hint_tag<Args...>{}, //
|
|
||||||
result);
|
|
||||||
|
|
||||||
// Invoke the callback
|
// Invoke the callback
|
||||||
packed_dispatch(std::move(static_cast<Base*>(this)->executor_),
|
packed_dispatch(std::move(static_cast<Base*>(this)->executor_),
|
||||||
@ -547,15 +565,13 @@ template <typename T, typename... Args>
|
|||||||
constexpr auto
|
constexpr auto
|
||||||
next_hint_of(std::integral_constant<handle_results, handle_results::yes>,
|
next_hint_of(std::integral_constant<handle_results, handle_results::yes>,
|
||||||
traits::identity<T> /*callback*/,
|
traits::identity<T> /*callback*/,
|
||||||
hints::signature_hint_tag<Args...> current) {
|
hints::signature_hint_tag<Args...> /*current*/) {
|
||||||
// Partial Invoke the given callback
|
// Partial Invoke the given callback
|
||||||
using Result = decltype(
|
using Result = decltype(
|
||||||
util::partial_invoke(std::declval<T>(), std::declval<Args>()...));
|
util::partial_invoke(std::declval<T>(), std::declval<Args>()...));
|
||||||
|
|
||||||
// Return the hint of thr given invoker
|
// Return the hint of thr given invoker
|
||||||
return decltype(decoration::invoker_of(current, //
|
return decltype(decoration::invoker_of(traits::identify<Result>{}).hint()){};
|
||||||
traits::identify<Result>{})
|
|
||||||
.hint()){};
|
|
||||||
}
|
}
|
||||||
/// Don't progress the hint when we don't continue
|
/// Don't progress the hint when we don't continue
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
|
|||||||
@ -39,7 +39,7 @@ cti::continuable<> resolve_async(S&& supplier) {
|
|||||||
co_await supplier();
|
co_await supplier();
|
||||||
|
|
||||||
// 1 args
|
// 1 args
|
||||||
co_await supplier(1);
|
int a1 = co_await supplier(1);
|
||||||
EXPECT_EQ(a1, 1);
|
EXPECT_EQ(a1, 1);
|
||||||
|
|
||||||
// 2-n args
|
// 2-n args
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user