8#include <userver/engine/impl/task_context_holder.hpp> 
    9#include <userver/engine/task/task.hpp> 
   10#include <userver/utils/fast_scope_guard.hpp> 
   11#include <userver/utils/impl/wrapped_call.hpp> 
   13USERVER_NAMESPACE_BEGIN
 
   15namespace engine::impl {
 
   17std::size_t GetTaskContextSize() 
noexcept;
 
   20inline constexpr std::size_t kTaskContextAlignment = 16;
 
   22struct TaskConfig 
final {
 
   23  engine::TaskProcessor& task_processor;
 
   26  engine::Deadline deadline;
 
   29[[nodiscard]] TaskContext& PlacementNewTaskContext(
 
   30    std::byte* storage, TaskConfig config,
 
   31    utils::impl::WrappedCallBase& payload);
 
   34std::byte* AllocateFusedTaskContext(std::size_t total_size);
 
   36void DeleteFusedTaskContext(std::byte* storage) 
noexcept;
 
   46template <
typename Function, 
typename... Args>
 
   47TaskContextHolder MakeTask(TaskConfig config, Function&& f, Args&&... args) {
 
   48  using WrappedCallType = utils::impl::WrappedCallImplType<Function, Args...>;
 
   50  constexpr auto kPayloadSize = 
sizeof(WrappedCallType);
 
   51  constexpr auto kPayloadAlignment = 
alignof(WrappedCallType);
 
   55  static_assert(kPayloadAlignment <= kTaskContextAlignment);
 
   57  const auto task_context_size = GetTaskContextSize();
 
   58  const auto total_size = task_context_size + kPayloadSize;
 
   60  std::byte* 
const storage = AllocateFusedTaskContext(total_size);
 
   61  utils::FastScopeGuard delete_guard{
 
   62      [&]() 
noexcept { DeleteFusedTaskContext(storage); }};
 
   64  std::byte* 
const payload_storage = storage + task_context_size;
 
   66  auto& payload = utils::impl::PlacementNewWrapCall(
 
   67      payload_storage, std::forward<Function>(f), std::forward<Args>(args)...);
 
   68  utils::FastScopeGuard destroy_payload_guard{
 
   69      [&]() 
noexcept { std::destroy_at(&payload); }};
 
   71  auto& context = PlacementNewTaskContext(storage, config, payload);
 
   73  destroy_payload_guard.Release();
 
   74  delete_guard.Release();
 
   75  return TaskContextHolder::Adopt(context);