mirror of
https://github.com/Naios/continuable.git
synced 2025-12-07 01:06:44 +08:00
Require make_continuable to be called with a valid signature
This commit is contained in:
parent
331d642e5d
commit
05b9223da8
@ -25,27 +25,27 @@
|
||||
#include "continuable/continuable.hpp"
|
||||
|
||||
cti::continuable<std::string> http_request(std::string /*url*/) {
|
||||
return cti::make_continuable<std::string>([](auto&& callback) {
|
||||
return [](auto&& callback) {
|
||||
// ...
|
||||
callback.set_value("<html>...</html>");
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
struct ResultSet {};
|
||||
struct Buffer {};
|
||||
|
||||
cti::continuable<ResultSet> mysql_query(std::string /*url*/) {
|
||||
return cti::make_continuable([](auto&& callback) {
|
||||
return [](auto&& callback) {
|
||||
// ...
|
||||
callback.set_value(ResultSet{});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
cti::continuable<Buffer> read_file(std::string /*url*/) {
|
||||
return cti::make_continuable([](auto&& callback) {
|
||||
return [](auto&& callback) {
|
||||
// ...
|
||||
callback.set_value(Buffer{});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
struct a {
|
||||
|
||||
@ -167,7 +167,7 @@ public:
|
||||
/// ```
|
||||
///
|
||||
/// \param executor The optional executor which is used to dispatch
|
||||
/// the callback. The executor needs to accept functional objects
|
||||
/// the callback. The executor needs to accept callable objects
|
||||
/// callable through an `operator()` through its operator() itself.
|
||||
/// The executor can be move-only, but it's not required to.
|
||||
/// The default executor which is used when omitting the argument
|
||||
@ -634,29 +634,30 @@ private:
|
||||
/// std::forward<decltype(callback)>(callback)();
|
||||
/// });
|
||||
/// ```
|
||||
/// * **No arguments** indicate that the types are unknown.
|
||||
/// * **No arguments** Since version 3.0.0 make_continuable always requires
|
||||
/// to be given valid arguments!
|
||||
/// You should always give the type hint a callback is called with because
|
||||
/// it's required for intermediate actions like connecting continuables.
|
||||
/// You may omit the signature hint if you are erasing the type of
|
||||
/// the continuable right after creation.
|
||||
/// ```cpp
|
||||
/// // Never do this:
|
||||
/// // This won't work because the arguments are missing:
|
||||
/// auto ct = cti::make_continuable([](auto&& callback) {
|
||||
/// std::forward<decltype(callback)>(callback)(0.f, 'c');
|
||||
/// });
|
||||
///
|
||||
/// // However, you may do this:
|
||||
/// continuable<float, char> ct = cti::make_continuable([](auto&& callback) {
|
||||
/// // However, you are allowed to do this:
|
||||
/// continuable<float, char> ct = [](auto&& callback) {
|
||||
/// std::forward<decltype(callback)>(callback)(0.f, 'c');
|
||||
/// });
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// \param continuation The continuation the continuable is created from.
|
||||
/// The continuation must be a functional type accepting a callback parameter
|
||||
/// The continuation must be a callable type accepting a callback parameter
|
||||
/// which represents the object invokable with the asynchronous result of this
|
||||
/// continuable.
|
||||
/// ```cpp
|
||||
/// auto ct = cti::make_continuable([](auto&& promise) {
|
||||
/// auto ct = cti::make_continuable<std::string>([](auto&& promise) {
|
||||
/// promise.set_value("result");
|
||||
/// });
|
||||
/// ```
|
||||
@ -666,11 +667,11 @@ private:
|
||||
/// It's recommended to accept any callback instead of erasing it.
|
||||
/// ```cpp
|
||||
/// // Good practice:
|
||||
/// auto ct = cti::make_continuable([](auto&& promise) {
|
||||
/// auto ct = cti::make_continuable<std::string>([](auto&& promise) {
|
||||
/// promise.set_value("result");
|
||||
/// });
|
||||
///
|
||||
/// // Good practice using a functional object:
|
||||
/// // Good practice using a callable object:
|
||||
/// struct Continuation {
|
||||
/// template<typename T>
|
||||
/// void operator() (T&& continuation) && {
|
||||
@ -678,10 +679,10 @@ private:
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// auto ct = cti::make_continuable(Continuation{});
|
||||
/// auto ct = cti::make_continuable<std::string>(Continuation{});
|
||||
///
|
||||
/// // Bad practice (because of unnecessary type erasure):
|
||||
/// auto ct = cti::make_continuable(
|
||||
/// auto ct = cti::make_continuable<std::string>(
|
||||
/// [](cti::promise<std::string> promise) {
|
||||
/// promise.set_value("result");
|
||||
/// });
|
||||
@ -698,12 +699,15 @@ private:
|
||||
/// \since 1.0.0
|
||||
template <typename... Args, typename Continuation>
|
||||
auto make_continuable(Continuation&& continuation) {
|
||||
auto hint = detail::composition::annotating::extract(
|
||||
detail::traits::identity_of(continuation),
|
||||
detail::traits::identity<Args...>{});
|
||||
static_assert(sizeof...(Args) > 0,
|
||||
"Since version 3.0.0 make_continuable requires an exact "
|
||||
"signature! If you did intend to create a void continuable "
|
||||
"use make_continuable<void>(...). Continuables with an exact "
|
||||
"signature may be created through make_continuable<Args...>.");
|
||||
|
||||
return detail::base::attorney::create(
|
||||
std::forward<Continuation>(continuation), hint,
|
||||
std::forward<Continuation>(continuation),
|
||||
detail::hints::extract(detail::traits::identity<Args...>{}),
|
||||
detail::util::ownership{});
|
||||
}
|
||||
|
||||
|
||||
@ -71,7 +71,7 @@ struct is_continuable<continuable_base<Data, Annotation>> : std::true_type {};
|
||||
/// the continuable_base class.
|
||||
struct attorney {
|
||||
/// Makes a continuation wrapper from the given argument
|
||||
template <typename T, typename A = hints::absent_signature_hint_tag>
|
||||
template <typename T, typename A>
|
||||
static auto create(T&& continuation, A /*hint*/, util::ownership ownership_) {
|
||||
return continuable_base<std::decay_t<T>, std::decay_t<A>>(
|
||||
std::forward<T>(continuation), ownership_);
|
||||
@ -107,7 +107,7 @@ struct attorney {
|
||||
// Returns the invoker of a callback, the next callback
|
||||
// and the arguments of the previous continuation.
|
||||
//
|
||||
// The return type of the invokerOf function matches a functional of:
|
||||
// The return type of the invokerOf function matches a callable of:
|
||||
// void(auto&& callback, auto&& next_callback, auto&&... args)
|
||||
//
|
||||
// The invoker decorates the result type in the following way
|
||||
@ -285,7 +285,7 @@ void packed_dispatch(Executor&& executor, Invoker&& invoker, Args&&... args) {
|
||||
});
|
||||
};
|
||||
|
||||
// Pass the work functional object to the executor
|
||||
// Pass the work callable object to the executor
|
||||
std::forward<Executor>(executor)(std::move(work));
|
||||
}
|
||||
|
||||
@ -568,7 +568,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Returns a continuable into a functional object returning the continuable
|
||||
/// Returns a continuable into a callable object returning the continuable
|
||||
template <typename Continuation>
|
||||
auto wrap_continuation(Continuation&& continuation) {
|
||||
continuation.freeze();
|
||||
|
||||
@ -59,52 +59,6 @@ struct is_strategy<strategy_all_tag> : std::true_type {};
|
||||
template <>
|
||||
struct is_strategy<strategy_any_tag> : std::true_type {};
|
||||
|
||||
/// Provides support for extracting the signature hint out
|
||||
/// of given types and parameters.
|
||||
namespace annotating {
|
||||
namespace detail {
|
||||
/// Void hints are equal to an empty signature
|
||||
constexpr auto make_hint_of(traits::identity<void>) noexcept {
|
||||
return hints::signature_hint_tag<>{};
|
||||
}
|
||||
/// All other hints are the obvious hints...
|
||||
template <typename... HintArgs>
|
||||
constexpr auto make_hint_of(traits::identity<HintArgs...> args) noexcept {
|
||||
return args; // Identity is equal to signature_hint_tag
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// Extracts the signature hint of a given continuation and it's optional
|
||||
/// present hint arguments.
|
||||
///
|
||||
/// There are 3 cases:
|
||||
/// - Any argument is given:
|
||||
/// -> The hint is of the argument type where void is equal to no args
|
||||
/// - An unwrappable type is given which first arguments signature is known
|
||||
/// -> The hint is of the mentioned signature
|
||||
/// - An object which signature isn't known
|
||||
/// -> The hint is unknown
|
||||
///
|
||||
/// In any cases the return type is a:
|
||||
/// - signature_hint_tag<?...> or a
|
||||
/// - absent_signature_hint_tag
|
||||
///
|
||||
template <typename T, typename... HintArgs>
|
||||
constexpr auto extract(traits::identity<T> /*type*/,
|
||||
traits::identity<HintArgs...> hint) {
|
||||
return traits::static_if(hint, traits::is_empty(),
|
||||
[=](auto /*hint*/) {
|
||||
/// When the arguments are the hint is absent
|
||||
return hints::absent_signature_hint_tag{};
|
||||
},
|
||||
[](auto hint) {
|
||||
// When hint arguments are given just take it as
|
||||
// hint
|
||||
return detail::make_hint_of(hint);
|
||||
});
|
||||
}
|
||||
} // namespace annotating
|
||||
|
||||
namespace detail {
|
||||
template <std::size_t Pos, typename T>
|
||||
constexpr void assign(traits::size_constant<Pos> /*pos*/, T& /*storage*/) {
|
||||
|
||||
@ -42,28 +42,28 @@ namespace hints {
|
||||
/// Represents a present signature hint
|
||||
template <typename... Args>
|
||||
using signature_hint_tag = traits::identity<Args...>;
|
||||
/// Represents an absent signature hint
|
||||
struct absent_signature_hint_tag {};
|
||||
|
||||
template <typename>
|
||||
struct is_absent_hint : std::false_type {};
|
||||
template <>
|
||||
struct is_absent_hint<absent_signature_hint_tag> : std::true_type {};
|
||||
|
||||
/// Returns the signature hint of the given continuable
|
||||
template <typename T>
|
||||
constexpr auto hint_of(traits::identity<T>) {
|
||||
static_assert(traits::fail<T>::value,
|
||||
"Expected a continuation with an existing signature hint!");
|
||||
return traits::identity<void>{};
|
||||
}
|
||||
/// Returns the signature hint of the given continuable
|
||||
template <typename Data, typename... Args>
|
||||
constexpr auto
|
||||
hint_of(traits::identity<
|
||||
continuable_base<Data, hints::signature_hint_tag<Args...>>>) {
|
||||
hint_of(traits::identity<continuable_base<Data, signature_hint_tag<Args...>>>) {
|
||||
return hints::signature_hint_tag<Args...>{};
|
||||
}
|
||||
|
||||
/// Extracts the signature we pass to the internal continuable
|
||||
/// from an argument pack as specified by make_continuable.
|
||||
///
|
||||
/// This is the overload taking an arbitrary amount of args
|
||||
template <typename... HintArgs>
|
||||
constexpr auto extract(traits::identity<HintArgs...> hint) {
|
||||
return hint;
|
||||
}
|
||||
/// \copybrief extract
|
||||
///
|
||||
/// This is the overload taking a void arg.
|
||||
constexpr auto extract(traits::identity<void> /*hint*/) {
|
||||
return traits::identity<>{};
|
||||
}
|
||||
} // namespace hints
|
||||
} // namespace detail
|
||||
} // namespace cti
|
||||
|
||||
@ -254,7 +254,7 @@ constexpr auto is_valid(T&& /*type*/, Check&& /*check*/) noexcept {
|
||||
return typename detail::is_valid_impl<T, Check>::type{};
|
||||
}
|
||||
|
||||
/// Creates a static functional validator object.
|
||||
/// Creates a static callable validation object.
|
||||
template <typename Check>
|
||||
constexpr auto validator_of(Check&& check) noexcept(
|
||||
std::is_nothrow_move_constructible<std::decay_t<Check>>::value) {
|
||||
|
||||
@ -29,7 +29,13 @@ TYPED_TEST(single_dimension_tests, is_eraseable) {
|
||||
|
||||
{
|
||||
cti::unique_continuable<int> erasure =
|
||||
cti::make_continuable(supplier_of(0xDF));
|
||||
cti::make_continuable<int>(supplier_of(0xDF));
|
||||
|
||||
EXPECT_ASYNC_RESULT(std::move(erasure), 0xDF);
|
||||
}
|
||||
|
||||
{
|
||||
cti::unique_continuable<int> erasure = supplier_of(0xDF);
|
||||
|
||||
EXPECT_ASYNC_RESULT(std::move(erasure), 0xDF);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user