sdbus-c++ 2.3.0
High-level C++ D-Bus library based on systemd D-Bus implementation
Loading...
Searching...
No Matches
Awaitable.h
Go to the documentation of this file.
1
27
28#ifndef SDBUS_CXX_AWAITABLE_H_
29#define SDBUS_CXX_AWAITABLE_H_
30
31#include <atomic>
32#include <cassert>
33#if __has_include(<coroutine>)
34#include <coroutine>
35#endif
36#include <cstdint>
37#include <exception>
38#include <memory>
39#include <type_traits>
40#include <variant>
41
42namespace sdbus {
43
44 // Forward declarations
46 namespace internal {
47 class Proxy;
48 } // namespace internal
49
50 /********************************************/
59 enum class AwaitableState : uint8_t
60 {
61 NotReady, // Initial state: callback hasn't fired yet
62 Waiting, // Coroutine is suspended and waiting for callback
63 Completed // Callback completed, result is ready
64 };
65
66 // Shared data
67 template <typename T>
69 {
70 using result_type = std::conditional_t<std::is_void_v<T>, std::monostate, T>;
71 std::variant<result_type, std::exception_ptr> result;
72 std::atomic<AwaitableState> status{AwaitableState::NotReady};
73#ifdef __cpp_lib_coroutine
74 // Keep the handle as the last member to mainting ABI compatibility
75 // with clients without coroutine support.
76 std::coroutine_handle<> handle;
77#endif // __cpp_lib_coroutine
78
79 void resumeCoroutine()
80 {
81#ifdef __cpp_lib_coroutine
82 handle.resume();
83#endif // __cpp_lib_coroutine
84 }
85 };
86
87 /********************************************/
108 template <typename T>
109 class Awaitable
110 {
111#ifdef __cpp_lib_coroutine
112 public:
113 // Called when the coroutine is co_await'ed. Returns true if the coroutine should be suspended.
114 [[nodiscard]] bool await_ready() const noexcept
115 {
116 return data_->status.load(std::memory_order_acquire) == AwaitableState::Completed;
117 }
118
119 // Called when the coroutine is suspended, returning false here will immediately
120 // resume the coroutine.
121 bool await_suspend(std::coroutine_handle<> handle) noexcept
122 {
123 data_->handle = handle;
124
125 // Attempt transition from NotReady to Waiting.
126 AwaitableState expected = AwaitableState::NotReady;
127 return data_->status.compare_exchange_strong(expected, AwaitableState::Waiting, std::memory_order_acq_rel);
128 }
129
130 // Called when the coroutine is resumed. Returns the result or throws the exception.
131 [[nodiscard]] T await_resume() const
132 {
133 if (auto* exception = std::get_if<std::exception_ptr>(&data_->result); exception != nullptr)
134 std::rethrow_exception(*exception);
135
136 if constexpr (std::is_void_v<T>)
137 return;
138 else
139 return std::get<T>(std::move(data_->result));
140 }
141#endif // __cpp_lib_coroutine
142
143 private:
144 friend internal::Proxy;
145 friend AsyncMethodInvoker;
146
147 explicit Awaitable(std::shared_ptr<AwaitableData<T>> data)
148 : data_(std::move(data))
149 {
150 assert(data_ != nullptr);
151 }
152
153 std::shared_ptr<AwaitableData<T>> data_;
154 };
155
156} // namespace sdbus
157
158#endif // SDBUS_CXX_AWAITABLE_H_
AwaitableState
Definition Awaitable.h:60
Definition ConvenienceApiClasses.h:128
Definition Awaitable.h:69