14#include <userver/utils/assert.hpp>
15#include <userver/utils/impl/wrapped_call_base.hpp>
16#include <userver/utils/lazy_prvalue.hpp>
17#include <userver/utils/result_store.hpp>
19USERVER_NAMESPACE_BEGIN
21namespace utils::impl {
25class WrappedCall :
public WrappedCallBase {
28 T Retrieve() {
return result_.Retrieve(); }
31 decltype(
auto) Get()
const& {
return result_.Get(); }
33 void RethrowErrorResult()
const final { (
void)result_.Get(); }
36 WrappedCall()
noexcept =
default;
38 ResultStore<T>& GetResultStore()
noexcept {
return result_; }
41 ResultStore<T> result_;
45WrappedCall<T>& CastWrappedCall(WrappedCallBase& wrapped_call)
noexcept {
46 UASSERT(
dynamic_cast<WrappedCall<T>*>(&wrapped_call) !=
nullptr);
48 return static_cast<WrappedCall<T>&>(wrapped_call);
52class OptionalSetNoneGuard
final {
54 OptionalSetNoneGuard(std::optional<T>& o)
noexcept : o_(o) {}
56 ~OptionalSetNoneGuard() { o_ = std::nullopt; }
63struct UnrefImpl
final {
68struct UnrefImpl<std::reference_wrapper<T>>
final {
72template <
typename Func>
73struct UnrefImpl<utils::LazyPrvalue<Func>>
final {
74 using type = std::invoke_result_t<Func&&>;
78using DecayUnref =
typename UnrefImpl<std::decay_t<T>>::type;
82template <
typename Function,
typename... Args>
83class WrappedCallImpl
final
84 :
public WrappedCall<std::invoke_result_t<Function&&, Args&&...>> {
86 using ResultType = std::invoke_result_t<Function&&, Args&&...>;
88 template <
typename RawFunction,
typename RawArgsTuple>
89 explicit WrappedCallImpl(RawFunction&& func, RawArgsTuple&& args)
90 : data_(std::in_place, std::forward<RawFunction>(func),
91 std::forward<RawArgsTuple>(args)) {}
93 void Perform() override {
95 if constexpr (std::is_pointer_v<Function>) {
96 UASSERT(data_->func !=
nullptr);
99 OptionalSetNoneGuard guard(data_);
100 auto& result =
this->GetResultStore();
105 if constexpr (std::is_void_v<ResultType>) {
106 std::apply(std::forward<Function>(data_->func), std::move(data_->args));
109 result.SetValue(std::apply(std::forward<Function>(data_->func),
110 std::move(data_->args)));
112 }
catch (
const std::exception&) {
113 result.SetException(std::current_exception());
120 template <
typename RawFunction,
typename RawArgsTuple>
121 explicit Data(RawFunction&& func, RawArgsTuple&& args)
123 : func(std::forward<RawFunction>(func)),
124 args(std::forward<RawArgsTuple>(args)) {}
127 std::tuple<Args...> args;
130 std::optional<Data> data_;
133template <
typename Function,
typename... Args>
134using WrappedCallImplType =
135 WrappedCallImpl<DecayUnref<Function>, DecayUnref<Args>...>;
140template <
typename Function,
typename... Args>
141[[nodiscard]]
auto& PlacementNewWrapCall(std::byte* storage, Function&& f,
144 (!std::is_array_v<std::remove_reference_t<Args>> && ...),
145 "Passing C arrays to Async is forbidden. Use std::array instead");
147 return *
new (storage) WrappedCallImplType<Function, Args...>(
148 std::forward<Function>(f),
149 std::forward_as_tuple(std::forward<Args>(args)...));