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"
|
#include "continuable/continuable.hpp"
|
||||||
|
|
||||||
cti::continuable<std::string> http_request(std::string /*url*/) {
|
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>");
|
callback.set_value("<html>...</html>");
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ResultSet {};
|
struct ResultSet {};
|
||||||
struct Buffer {};
|
struct Buffer {};
|
||||||
|
|
||||||
cti::continuable<ResultSet> mysql_query(std::string /*url*/) {
|
cti::continuable<ResultSet> mysql_query(std::string /*url*/) {
|
||||||
return cti::make_continuable([](auto&& callback) {
|
return [](auto&& callback) {
|
||||||
// ...
|
// ...
|
||||||
callback.set_value(ResultSet{});
|
callback.set_value(ResultSet{});
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
cti::continuable<Buffer> read_file(std::string /*url*/) {
|
cti::continuable<Buffer> read_file(std::string /*url*/) {
|
||||||
return cti::make_continuable([](auto&& callback) {
|
return [](auto&& callback) {
|
||||||
// ...
|
// ...
|
||||||
callback.set_value(Buffer{});
|
callback.set_value(Buffer{});
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct a {
|
struct a {
|
||||||
|
|||||||
@ -167,7 +167,7 @@ public:
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// \param executor The optional executor which is used to dispatch
|
/// \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.
|
/// callable through an `operator()` through its operator() itself.
|
||||||
/// The executor can be move-only, but it's not required to.
|
/// The executor can be move-only, but it's not required to.
|
||||||
/// The default executor which is used when omitting the argument
|
/// The default executor which is used when omitting the argument
|
||||||
@ -634,29 +634,30 @@ private:
|
|||||||
/// std::forward<decltype(callback)>(callback)();
|
/// 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
|
/// You should always give the type hint a callback is called with because
|
||||||
/// it's required for intermediate actions like connecting continuables.
|
/// it's required for intermediate actions like connecting continuables.
|
||||||
/// You may omit the signature hint if you are erasing the type of
|
/// You may omit the signature hint if you are erasing the type of
|
||||||
/// the continuable right after creation.
|
/// the continuable right after creation.
|
||||||
/// ```cpp
|
/// ```cpp
|
||||||
/// // Never do this:
|
/// // This won't work because the arguments are missing:
|
||||||
/// auto ct = cti::make_continuable([](auto&& callback) {
|
/// auto ct = cti::make_continuable([](auto&& callback) {
|
||||||
/// std::forward<decltype(callback)>(callback)(0.f, 'c');
|
/// std::forward<decltype(callback)>(callback)(0.f, 'c');
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// // However, you may do this:
|
/// // However, you are allowed to do this:
|
||||||
/// continuable<float, char> ct = cti::make_continuable([](auto&& callback) {
|
/// continuable<float, char> ct = [](auto&& callback) {
|
||||||
/// std::forward<decltype(callback)>(callback)(0.f, 'c');
|
/// std::forward<decltype(callback)>(callback)(0.f, 'c');
|
||||||
/// });
|
/// };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// \param continuation The continuation the continuable is created from.
|
/// \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
|
/// which represents the object invokable with the asynchronous result of this
|
||||||
/// continuable.
|
/// continuable.
|
||||||
/// ```cpp
|
/// ```cpp
|
||||||
/// auto ct = cti::make_continuable([](auto&& promise) {
|
/// auto ct = cti::make_continuable<std::string>([](auto&& promise) {
|
||||||
/// promise.set_value("result");
|
/// promise.set_value("result");
|
||||||
/// });
|
/// });
|
||||||
/// ```
|
/// ```
|
||||||
@ -666,11 +667,11 @@ private:
|
|||||||
/// It's recommended to accept any callback instead of erasing it.
|
/// It's recommended to accept any callback instead of erasing it.
|
||||||
/// ```cpp
|
/// ```cpp
|
||||||
/// // Good practice:
|
/// // Good practice:
|
||||||
/// auto ct = cti::make_continuable([](auto&& promise) {
|
/// auto ct = cti::make_continuable<std::string>([](auto&& promise) {
|
||||||
/// promise.set_value("result");
|
/// promise.set_value("result");
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// // Good practice using a functional object:
|
/// // Good practice using a callable object:
|
||||||
/// struct Continuation {
|
/// struct Continuation {
|
||||||
/// template<typename T>
|
/// template<typename T>
|
||||||
/// void operator() (T&& continuation) && {
|
/// 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):
|
/// // Bad practice (because of unnecessary type erasure):
|
||||||
/// auto ct = cti::make_continuable(
|
/// auto ct = cti::make_continuable<std::string>(
|
||||||
/// [](cti::promise<std::string> promise) {
|
/// [](cti::promise<std::string> promise) {
|
||||||
/// promise.set_value("result");
|
/// promise.set_value("result");
|
||||||
/// });
|
/// });
|
||||||
@ -698,12 +699,15 @@ private:
|
|||||||
/// \since 1.0.0
|
/// \since 1.0.0
|
||||||
template <typename... Args, typename Continuation>
|
template <typename... Args, typename Continuation>
|
||||||
auto make_continuable(Continuation&& continuation) {
|
auto make_continuable(Continuation&& continuation) {
|
||||||
auto hint = detail::composition::annotating::extract(
|
static_assert(sizeof...(Args) > 0,
|
||||||
detail::traits::identity_of(continuation),
|
"Since version 3.0.0 make_continuable requires an exact "
|
||||||
detail::traits::identity<Args...>{});
|
"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(
|
return detail::base::attorney::create(
|
||||||
std::forward<Continuation>(continuation), hint,
|
std::forward<Continuation>(continuation),
|
||||||
|
detail::hints::extract(detail::traits::identity<Args...>{}),
|
||||||
detail::util::ownership{});
|
detail::util::ownership{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -71,7 +71,7 @@ struct is_continuable<continuable_base<Data, Annotation>> : std::true_type {};
|
|||||||
/// the continuable_base class.
|
/// the continuable_base class.
|
||||||
struct attorney {
|
struct attorney {
|
||||||
/// Makes a continuation wrapper from the given argument
|
/// 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_) {
|
static auto create(T&& continuation, A /*hint*/, util::ownership ownership_) {
|
||||||
return continuable_base<std::decay_t<T>, std::decay_t<A>>(
|
return continuable_base<std::decay_t<T>, std::decay_t<A>>(
|
||||||
std::forward<T>(continuation), ownership_);
|
std::forward<T>(continuation), ownership_);
|
||||||
@ -107,7 +107,7 @@ struct attorney {
|
|||||||
// Returns the invoker of a callback, the next callback
|
// Returns the invoker of a callback, the next callback
|
||||||
// and the arguments of the previous continuation.
|
// 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)
|
// void(auto&& callback, auto&& next_callback, auto&&... args)
|
||||||
//
|
//
|
||||||
// The invoker decorates the result type in the following way
|
// 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));
|
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>
|
template <typename Continuation>
|
||||||
auto wrap_continuation(Continuation&& continuation) {
|
auto wrap_continuation(Continuation&& continuation) {
|
||||||
continuation.freeze();
|
continuation.freeze();
|
||||||
|
|||||||
@ -59,53 +59,7 @@ struct is_strategy<strategy_all_tag> : std::true_type {};
|
|||||||
template <>
|
template <>
|
||||||
struct is_strategy<strategy_any_tag> : std::true_type {};
|
struct is_strategy<strategy_any_tag> : std::true_type {};
|
||||||
|
|
||||||
/// Provides support for extracting the signature hint out
|
namespace detail {
|
||||||
/// 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>
|
template <std::size_t Pos, typename T>
|
||||||
constexpr void assign(traits::size_constant<Pos> /*pos*/, T& /*storage*/) {
|
constexpr void assign(traits::size_constant<Pos> /*pos*/, T& /*storage*/) {
|
||||||
// ...
|
// ...
|
||||||
|
|||||||
@ -42,28 +42,28 @@ namespace hints {
|
|||||||
/// Represents a present signature hint
|
/// Represents a present signature hint
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
using signature_hint_tag = traits::identity<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
|
/// Returns the signature hint of the given continuable
|
||||||
template <typename Data, typename... Args>
|
template <typename Data, typename... Args>
|
||||||
constexpr auto
|
constexpr auto
|
||||||
hint_of(traits::identity<
|
hint_of(traits::identity<continuable_base<Data, signature_hint_tag<Args...>>>) {
|
||||||
continuable_base<Data, hints::signature_hint_tag<Args...>>>) {
|
|
||||||
return hints::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 hints
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace cti
|
} // namespace cti
|
||||||
|
|||||||
@ -254,7 +254,7 @@ constexpr auto is_valid(T&& /*type*/, Check&& /*check*/) noexcept {
|
|||||||
return typename detail::is_valid_impl<T, Check>::type{};
|
return typename detail::is_valid_impl<T, Check>::type{};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a static functional validator object.
|
/// Creates a static callable validation object.
|
||||||
template <typename Check>
|
template <typename Check>
|
||||||
constexpr auto validator_of(Check&& check) noexcept(
|
constexpr auto validator_of(Check&& check) noexcept(
|
||||||
std::is_nothrow_move_constructible<std::decay_t<Check>>::value) {
|
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::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);
|
EXPECT_ASYNC_RESULT(std::move(erasure), 0xDF);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user