1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_async2/once_sender.h"
16
17 #include "pw_async2/dispatcher.h"
18 #include "pw_containers/vector.h"
19 #include "pw_unit_test/framework.h"
20
21 namespace {
22
23 using ::pw::async2::Context;
24 using ::pw::async2::Dispatcher;
25 using ::pw::async2::OnceReceiver;
26 using ::pw::async2::OnceRefReceiver;
27 using ::pw::async2::OnceRefSender;
28 using ::pw::async2::OnceSender;
29 using ::pw::async2::Pending;
30 using ::pw::async2::Poll;
31 using ::pw::async2::Ready;
32 using ::pw::async2::Task;
33
34 class MoveOnlyValue {
35 public:
MoveOnlyValue(int value)36 MoveOnlyValue(int value) : value_(value) {}
37 MoveOnlyValue(const MoveOnlyValue&) = delete;
38 MoveOnlyValue& operator=(const MoveOnlyValue&) = delete;
39 MoveOnlyValue(MoveOnlyValue&&) = default;
40 MoveOnlyValue& operator=(MoveOnlyValue&&) = default;
41
value()42 int& value() { return value_; }
43
44 private:
45 int value_;
46 };
47
48 class ValueTask : public Task {
49 public:
ValueTask(bool use_make_constructor=true)50 ValueTask(bool use_make_constructor = true)
51 : use_make_constructor_(use_make_constructor) {}
DoPend(Context & cx)52 Poll<> DoPend(Context& cx) override {
53 if (!receiver_) {
54 if (use_make_constructor_) {
55 auto [send, recv] =
56 pw::async2::MakeOnceSenderAndReceiver<MoveOnlyValue>();
57 sender_.emplace(std::move(send));
58 receiver_.emplace(std::move(recv));
59 } else {
60 receiver_.emplace();
61 sender_.emplace();
62 pw::async2::InitializeOnceSenderAndReceiver<MoveOnlyValue>(
63 sender_.value(), receiver_.value());
64 }
65 }
66 Poll<pw::Result<MoveOnlyValue>> poll = receiver_.value().Pend(cx);
67 if (poll.IsReady()) {
68 ready_value_.emplace(std::move(poll.value()));
69 return Ready();
70 }
71 return Pending();
72 }
ready_value()73 std::optional<pw::Result<MoveOnlyValue>>& ready_value() {
74 return ready_value_;
75 }
sender()76 std::optional<OnceSender<MoveOnlyValue>>& sender() { return sender_; }
77
DestroySender()78 void DestroySender() { sender_.reset(); }
DestroyReceiver()79 void DestroyReceiver() { receiver_.reset(); }
80
81 private:
82 bool use_make_constructor_;
83 std::optional<pw::Result<MoveOnlyValue>> ready_value_;
84 std::optional<OnceReceiver<MoveOnlyValue>> receiver_;
85 std::optional<OnceSender<MoveOnlyValue>> sender_;
86 };
87
TEST(OnceSender,OnceSenderEmplace)88 TEST(OnceSender, OnceSenderEmplace) {
89 Dispatcher dispatcher;
90 ValueTask task;
91 dispatcher.Post(task);
92 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
93
94 task.sender()->emplace(5);
95 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
96
97 ASSERT_TRUE(task.ready_value().has_value());
98 ASSERT_TRUE(task.ready_value().value().ok());
99 EXPECT_EQ(task.ready_value().value()->value(), 5);
100 }
101
TEST(OnceSender,OnceSenderEmplaceUseInitializeConstructor)102 TEST(OnceSender, OnceSenderEmplaceUseInitializeConstructor) {
103 Dispatcher dispatcher;
104 ValueTask task(/*use_make_constructor=*/false);
105 dispatcher.Post(task);
106 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
107
108 task.sender()->emplace(5);
109 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
110
111 ASSERT_TRUE(task.ready_value().has_value());
112 ASSERT_TRUE(task.ready_value().value().ok());
113 EXPECT_EQ(task.ready_value().value()->value(), 5);
114 }
115
TEST(OnceSender,OnceSenderMoveAssign)116 TEST(OnceSender, OnceSenderMoveAssign) {
117 Dispatcher dispatcher;
118 ValueTask task;
119 dispatcher.Post(task);
120 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
121
122 MoveOnlyValue value(7);
123 *task.sender() = std::move(value);
124 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
125
126 ASSERT_TRUE(task.ready_value().has_value());
127 ASSERT_TRUE(task.ready_value().value().ok());
128 EXPECT_EQ(task.ready_value().value()->value(), 7);
129 }
130
TEST(OnceSender,DestroyingOnceSenderCausesReceiverPendToReturnCancelled)131 TEST(OnceSender, DestroyingOnceSenderCausesReceiverPendToReturnCancelled) {
132 Dispatcher dispatcher;
133 ValueTask task;
134 dispatcher.Post(task);
135 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
136
137 task.DestroySender();
138 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
139 task.DestroyReceiver();
140
141 ASSERT_TRUE(task.ready_value().has_value());
142 ASSERT_FALSE(task.ready_value().value().ok());
143 ASSERT_TRUE(task.ready_value().value().status().IsCancelled());
144 }
145
TEST(OnceSender,DestroyingOnceReceiverCausesSenderMethodsToBeNoOps)146 TEST(OnceSender, DestroyingOnceReceiverCausesSenderMethodsToBeNoOps) {
147 Dispatcher dispatcher;
148 ValueTask task;
149 dispatcher.Post(task);
150 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
151
152 task.DestroyReceiver();
153 task.sender()->emplace(6);
154 task.DestroySender();
155 task.Deregister();
156 }
157
158 class VectorTask : public Task {
159 public:
VectorTask(bool use_make_constructor=true)160 VectorTask(bool use_make_constructor = true)
161 : use_make_constructor_(use_make_constructor) {}
162
DoPend(Context & cx)163 Poll<> DoPend(Context& cx) override {
164 if (!receiver_) {
165 if (use_make_constructor_) {
166 auto [send, recv] =
167 pw::async2::MakeOnceRefSenderAndReceiver<pw::Vector<int>>(value_);
168 sender_.emplace(std::move(send));
169 receiver_.emplace(std::move(recv));
170 } else {
171 sender_.emplace();
172 receiver_.emplace();
173 pw::async2::InitializeOnceRefSenderAndReceiver<pw::Vector<int>>(
174 sender_.value(), receiver_.value(), value_);
175 }
176 }
177 Poll<pw::Status> poll = receiver_->Pend(cx);
178 if (poll.IsReady()) {
179 ready_value_.emplace(poll.value());
180 return Ready();
181 }
182 return Pending();
183 }
184
value() const185 const pw::Vector<int>& value() const { return value_; }
ready_value() const186 const std::optional<pw::Status>& ready_value() const { return ready_value_; }
sender()187 std::optional<OnceRefSender<pw::Vector<int>>>& sender() { return sender_; }
188
DestroySender()189 void DestroySender() { sender_.reset(); }
DestroyReceiver()190 void DestroyReceiver() { receiver_.reset(); }
191
192 private:
193 bool use_make_constructor_;
194 pw::Vector<int, 3> value_;
195 std::optional<pw::Status> ready_value_;
196 std::optional<OnceRefReceiver<pw::Vector<int>>> receiver_;
197 std::optional<OnceRefSender<pw::Vector<int>>> sender_;
198 };
199
TEST(OnceSender,OnceRefSenderSetConstRef)200 TEST(OnceSender, OnceRefSenderSetConstRef) {
201 Dispatcher dispatcher;
202 VectorTask task;
203 dispatcher.Post(task);
204 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
205
206 pw::Vector<int, 2> other = {0, 1};
207 task.sender()->Set(other);
208 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
209 EXPECT_EQ(task.value()[0], 0);
210 EXPECT_EQ(task.value()[1], 1);
211 }
212
TEST(OnceSender,OnceRefSenderSetConstRefUseInitializeConstructor)213 TEST(OnceSender, OnceRefSenderSetConstRefUseInitializeConstructor) {
214 Dispatcher dispatcher;
215 VectorTask task(/*use_make_constructor=*/false);
216 dispatcher.Post(task);
217 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
218
219 pw::Vector<int, 2> other = {0, 1};
220 task.sender()->Set(other);
221 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
222 EXPECT_EQ(task.value()[0], 0);
223 EXPECT_EQ(task.value()[1], 1);
224 }
225
TEST(OnceSender,OnceRefSenderModify)226 TEST(OnceSender, OnceRefSenderModify) {
227 Dispatcher dispatcher;
228 VectorTask task;
229 dispatcher.Post(task);
230 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
231
232 task.sender()->ModifyUnsafe([](pw::Vector<int>& vec) { vec.push_back(0); });
233 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
234
235 task.sender()->ModifyUnsafe([](pw::Vector<int>& vec) { vec.push_back(1); });
236 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
237
238 task.sender()->Commit();
239 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
240 EXPECT_EQ(task.value()[0], 0);
241 EXPECT_EQ(task.value()[1], 1);
242 }
243
TEST(OnceSender,DestroyingOnceRefSenderCausesReceiverPendToReturnCancelled)244 TEST(OnceSender, DestroyingOnceRefSenderCausesReceiverPendToReturnCancelled) {
245 Dispatcher dispatcher;
246 VectorTask task;
247 dispatcher.Post(task);
248 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
249
250 task.DestroySender();
251 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
252 task.DestroyReceiver();
253
254 ASSERT_TRUE(task.ready_value().has_value());
255 ASSERT_TRUE(task.ready_value().value().IsCancelled());
256 }
257
258 class MoveOnlyRefTask : public Task {
259 public:
DoPend(Context & cx)260 Poll<> DoPend(Context& cx) override {
261 if (!receiver_) {
262 auto [send, recv] =
263 pw::async2::MakeOnceRefSenderAndReceiver<MoveOnlyValue>(value_);
264 sender_.emplace(std::move(send));
265 receiver_.emplace(std::move(recv));
266 }
267 Poll<pw::Status> poll = receiver_->Pend(cx);
268 if (poll.IsReady()) {
269 ready_value_.emplace(poll.value());
270 return Ready();
271 }
272 return Pending();
273 }
274
value()275 MoveOnlyValue& value() { return value_; }
ready_value()276 std::optional<pw::Status>& ready_value() { return ready_value_; }
sender()277 std::optional<OnceRefSender<MoveOnlyValue>>& sender() { return sender_; }
278
279 private:
280 MoveOnlyValue value_{0};
281 std::optional<pw::Status> ready_value_;
282 std::optional<OnceRefReceiver<MoveOnlyValue>> receiver_;
283 std::optional<OnceRefSender<MoveOnlyValue>> sender_;
284 };
285
TEST(OnceSender,OnceRefSenderSetRValue)286 TEST(OnceSender, OnceRefSenderSetRValue) {
287 Dispatcher dispatcher;
288 MoveOnlyRefTask task;
289 dispatcher.Post(task);
290 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsPending());
291
292 MoveOnlyValue value2(2);
293 task.sender()->Set(std::move(value2));
294 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
295 ASSERT_TRUE(task.ready_value().has_value());
296 ASSERT_TRUE(task.ready_value()->ok());
297 EXPECT_EQ(task.value().value(), 2);
298 }
299
300 class AlreadyCompletedReceiverTask : public Task {
301 public:
AlreadyCompletedReceiverTask(OnceReceiver<MoveOnlyValue> receiver)302 AlreadyCompletedReceiverTask(OnceReceiver<MoveOnlyValue> receiver)
303 : receiver_(std::move(receiver)) {}
304
DoPend(Context & cx)305 Poll<> DoPend(Context& cx) override {
306 Poll<pw::Result<MoveOnlyValue>> poll = receiver_.Pend(cx);
307 if (poll.IsReady()) {
308 ready_value_.emplace(std::move(poll.value()));
309 return Ready();
310 }
311 return Pending();
312 }
313
ready_value()314 std::optional<pw::Result<MoveOnlyValue>>& ready_value() {
315 return ready_value_;
316 }
317
318 private:
319 std::optional<pw::Result<MoveOnlyValue>> ready_value_;
320 OnceReceiver<MoveOnlyValue> receiver_;
321 };
322
TEST(OnceSender,OnceReceiverAlreadyCompleted)323 TEST(OnceSender, OnceReceiverAlreadyCompleted) {
324 Dispatcher dispatcher;
325 OnceReceiver<MoveOnlyValue> receiver(2);
326 AlreadyCompletedReceiverTask task(std::move(receiver));
327 dispatcher.Post(task);
328 EXPECT_TRUE(dispatcher.RunUntilStalled(task).IsReady());
329 ASSERT_TRUE(task.ready_value().has_value());
330 ASSERT_TRUE(task.ready_value()->ok());
331 EXPECT_EQ(task.ready_value()->value().value(), 2);
332 }
333
334 } // namespace
335