userver: userver/engine/task/task_with_result.hpp Source File
Loading...
Searching...
No Matches
task_with_result.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/task/task_with_result.hpp
4/// @brief @copybrief engine::TaskWithResult
5
6#include <memory>
7#include <stdexcept>
8#include <utility>
9
10#include <userver/engine/exception.hpp>
11#include <userver/engine/impl/task_context_holder.hpp>
12#include <userver/engine/task/task.hpp>
13#include <userver/utils/fast_scope_guard.hpp>
14#include <userver/utils/impl/wrapped_call.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace engine {
19
20/// Asynchronous task with result
21///
22/// @warning This class supports only a single concurrent awaiter. Use
23/// @ref engine::SharedTaskWithResult to await and retrieve the same result from
24/// multiple coroutines.
25///
26/// ## Example usage:
27///
28/// @snippet core/src/engine/task/task_with_result_test.cpp Sample TaskWithResult usage
29///
30/// @see @ref scripts/docs/en/userver/synchronization.md
31template <typename T>
32class [[nodiscard]] TaskWithResult : public Task {
33public:
34 /// @brief Default constructor
35 ///
36 /// Creates an invalid task.
37 TaskWithResult() = default;
38
39 TaskWithResult(const TaskWithResult&) = delete;
40 TaskWithResult& operator=(const TaskWithResult&) = delete;
41
42 /// @brief Moves the other task into this, leaving the other in an invalid
43 /// state.
44 TaskWithResult(TaskWithResult&& other) noexcept = default;
45
46 /// @brief If this Task is still valid and is not finished, cancels it and
47 /// waits until it finishes before moving the other. Otherwise just moves the
48 /// other task into this, leaving the other in invalid state.
49 TaskWithResult& operator=(TaskWithResult&& other) noexcept = default;
50
51 /// @brief Returns (or rethrows) the result of task invocation.
52 /// After return from this method the task is not valid.
53 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
54 /// and no TaskCancellationBlockers are present.
55 /// @throws TaskCancelledException
56 /// if no result is available because the task was cancelled
57 T Get() noexcept(false) {
58 EnsureValid();
59
60 Wait();
61 const utils::FastScopeGuard invalidate([this]() noexcept { Invalidate(); });
64 }
65
66 return utils::impl::CastWrappedCall<T>(GetPayload()).Retrieve();
67 }
68
69 /// Satisfies @ref engine::Awaitable, for use with @ref engine::WaitAnyContext and friends.
70 using Task::GetAwaitableToken;
71
72 /// @cond
73 static constexpr WaitMode kWaitMode = WaitMode::kSingleAwaiter;
74
75 // For internal use only.
76 explicit TaskWithResult(impl::TaskContextHolder&& context)
77 : Task(std::move(context))
78 {}
79 /// @endcond
80
81 Task AsTask() && {
82 // NOLINTNEXTLINE(cppcoreguidelines-slicing)
83 return std::move(*this);
84 }
85
86private:
87 void EnsureValid() const {
90 "TaskWithResult::Get was called on an invalid task. Note that "
91 "Get invalidates self, so it must be called at most once "
92 "per task"
93 );
94 }
95};
96
97} // namespace engine
98
99USERVER_NAMESPACE_END