29 std::optional<T> Slot_;
30 std::coroutine_handle<> Handle_;
31 bool Registered_ =
false;
33 explicit ReceiveAwaiter (
Channel& ch)
42 std::lock_guard guard { Ch_.Lock_ };
43 std::erase (Ch_.Awaiters_,
this);
48 Ch_.SendImpl (std::move (*Slot_), SendClosedBehavior::Ignore);
51 bool await_ready ()
const noexcept
56 bool await_suspend (std::coroutine_handle<> handle)
58 std::lock_guard guard { Ch_.Lock_ };
59 if (!Ch_.Elems_.empty ())
61 Slot_ = std::move (Ch_.Elems_.front ());
62 Ch_.Elems_.pop_front ();
69 Ch_.Awaiters_.push_back (
this);
75 std::optional<T> await_resume ()
78 return std::exchange (Slot_, {});
80 std::lock_guard guard { Ch_.Lock_ };
81 if (Ch_.Elems_.empty ())
83 auto value = std::move (Ch_.Elems_.front ());
84 Ch_.Elems_.pop_front ();
89 mutable std::mutex Lock_;
91 std::deque<ReceiveAwaiter*> Awaiters_;
107 std::lock_guard guard { Lock_ };
108 if (std::exchange (Closed_,
true))
112 while (
const auto next = PopNextAwaiter ())
116 template<
typename U = T>
119 SendImpl (std::forward<U> (value), SendClosedBehavior::Throw);
124 std::lock_guard guard { Lock_ };
125 return Elems_.empty ();
130 return ReceiveAwaiter { *
this };
133 auto operator co_await ()
138 enum class SendClosedBehavior : std::uint8_t { Ignore, Throw };
140 template<
typename U = T>
141 void SendImpl (U&& value, SendClosedBehavior closedBehavior)
143 const auto next = [&]
145 std::lock_guard guard { Lock_ };
146 if (Closed_ && closedBehavior == SendClosedBehavior::Throw)
147 throw std::runtime_error {
"sending into a closed channel" };
149 const auto awaiter = PopNextAwaiterUnlocked ();
151 Elems_.emplace_back (std::forward<U> (value));
157 next->Slot_.emplace (std::forward<U> (value));
162 ReceiveAwaiter* PopNextAwaiter ()
164 std::lock_guard guard { Lock_ };
165 return PopNextAwaiterUnlocked ();
168 ReceiveAwaiter* PopNextAwaiterUnlocked ()
170 if (Awaiters_.empty ())
172 auto next = Awaiters_.front ();
173 Awaiters_.pop_front ();
174 next->Registered_ =
false;
178 void Invoke (ReceiveAwaiter& awaiter)
180 QMetaObject::invokeMethod (&awaiter.Ctx_,
181 [&awaiter] { awaiter.Handle_ (); },
182 Qt::QueuedConnection);