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)...));