Github   Telegram
Loading...
Searching...
No Matches
future_state.hpp
1#pragma once
2
3#include <atomic>
4#include <exception>
5
6#include <userver/engine/deadline.hpp>
7#include <userver/engine/future_status.hpp>
8#include <userver/engine/impl/context_accessor.hpp>
9#include <userver/engine/impl/wait_list_fwd.hpp>
10#include <userver/utils/result_store.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace engine::impl {
15
16class FutureStateBase : private engine::impl::ContextAccessor {
17 public:
18 bool IsReady() const noexcept final;
19
20 [[nodiscard]] FutureStatus WaitUntil(Deadline deadline);
21
22 void OnFutureCreated();
23
24 // Internal helper for WaitAny/WaitAll
25 ContextAccessor* TryGetContextAccessor() noexcept { return this; }
26
27 protected:
28 class WaitStrategy;
29
30 FutureStateBase() noexcept;
31 ~FutureStateBase();
32
33 void LockResultStore();
34 void ReleaseResultStore();
35 void WaitForResult();
36
37 private:
38 void AppendWaiter(impl::TaskContext& context) noexcept final;
39 void RemoveWaiter(impl::TaskContext& context) noexcept final;
40
41 FastPimplWaitListLight finish_waiters_;
42 std::atomic<bool> is_ready_;
43 std::atomic<bool> is_result_store_locked_;
44 std::atomic<bool> is_future_created_;
45};
46
47template <typename T>
48class FutureState final : public FutureStateBase {
49 public:
50 [[nodiscard]] T Get();
51
52 void SetValue(const T& value);
53 void SetValue(T&& value);
54 void SetException(std::exception_ptr&& ex);
55
56 private:
57 void RethrowErrorResult() const override;
58
59 utils::ResultStore<T> result_store_;
60};
61
62template <>
63class FutureState<void> final : public FutureStateBase {
64 public:
65 void Get();
66
67 void SetValue();
68 void SetException(std::exception_ptr&& ex);
69
70 private:
71 void RethrowErrorResult() const override;
72
73 utils::ResultStore<void> result_store_;
74};
75
76template <typename T>
77T FutureState<T>::Get() {
78 WaitForResult();
79 return result_store_.Retrieve();
80}
81
82template <typename T>
83void FutureState<T>::SetValue(const T& value) {
84 LockResultStore();
85 result_store_.SetValue(value);
86 ReleaseResultStore();
87}
88
89template <typename T>
90void FutureState<T>::SetValue(T&& value) {
91 LockResultStore();
92 result_store_.SetValue(std::move(value));
93 ReleaseResultStore();
94}
95
96template <typename T>
97void FutureState<T>::SetException(std::exception_ptr&& ex) {
98 LockResultStore();
99 result_store_.SetException(std::move(ex));
100 ReleaseResultStore();
101}
102
103template <typename T>
104void FutureState<T>::RethrowErrorResult() const {
105 (void)result_store_.Get();
106}
107
108inline void FutureState<void>::Get() {
109 WaitForResult();
110 return result_store_.Retrieve();
111}
112
113inline void FutureState<void>::SetValue() {
114 LockResultStore();
115 result_store_.SetValue();
116 ReleaseResultStore();
117}
118
119inline void FutureState<void>::SetException(std::exception_ptr&& ex) {
120 LockResultStore();
121 result_store_.SetException(std::move(ex));
122 ReleaseResultStore();
123}
124
125inline void FutureState<void>::RethrowErrorResult() const {
126 (void)result_store_.Get();
127}
128
129} // namespace engine::impl
130
131USERVER_NAMESPACE_END